UGUI刘海屏处理(一)

2021/09 16 23:09
using UnityEngine;
using UnityEngine.UI;

public class UguiAutoResolution : MonoBehaviour
{
    private DeviceDir mCurrDeviceDir = DeviceDir.None;
    private RectInt mSafeArea = new RectInt(0, 0, 0, 0);
    private Vector2Int mCurrentScreenSize = Vector2Int.zero;
    private const int kChangeDirty = 10; // 10帧,用于延后生效
    private const int kReferenceResolutionHeight = 720; // 固定设计分辨率
    private const int kReferenceResolutionWidth = 1280; // 固定设计分辨率
    private readonly static Vector2Int kReferenceResolution_horz = new Vector2Int(kReferenceResolutionWidth, kReferenceResolutionHeight);
    private readonly static Vector2Int kReferenceResolution_vert = new Vector2Int(kReferenceResolutionHeight, kReferenceResolutionWidth);
    private int mChanged = 0;
    private static RectInt _safeArea = new RectInt();
    private static RectInt ScreenSafeArea
    {
        get
        {
            var s = Screen.safeArea;
            _safeArea.x = (int)s.x;
            _safeArea.y = (int)s.y;
            _safeArea.width = (int)s.width;
            _safeArea.height = (int)s.height;
            return _safeArea;
        }
    }  

    enum DeviceDir
    {
        None,
        Horz,
        Vert,
    };

    void Start()
    {
        UpdateResolution();
    }

    private float GetScreenMinRate()
    {
        return Mathf.Min( Screen.width, Screen.height ) / (float)kReferenceResolutionHeight;
    }

    private void OnResolutionChange()
    {
        var safeArea = ScreenSafeArea;
        var rate = GetScreenMinRate();
        var canvasScaler = this.GetComponent<CanvasScaler>();
        if (canvasScaler != null)
        {
            canvasScaler.referenceResolution = Screen.width > Screen.height?  kReferenceResolution_horz: kReferenceResolution_vert;
        }

        var xMin = safeArea.xMin / rate;
        var yMin = safeArea.yMin / rate;
        var xMax = (safeArea.xMax - Screen.width)  / rate;
        var yMax = (safeArea.yMax - Screen.height) / rate;

        var offsetMin = new Vector2(xMin, yMin);
        var offsetMax = new Vector2(xMax, yMax);

        var selfTrans = this.gameObject.transform;
        var childCount = selfTrans.childCount;

        for(int i=0; i<childCount; ++i)
        {
            var childRectTrans = selfTrans.GetChild(i).GetComponent<RectTransform>();
            if (childRectTrans != null)
            {
                childRectTrans.offsetMin = offsetMin;
                childRectTrans.offsetMax = offsetMax;
            }
        }
    }

    private static DeviceDir GetDeviceDir(DeviceOrientation devOri)
    {
        switch(devOri)
        {
            case DeviceOrientation.Portrait: return DeviceDir.Vert;
            case DeviceOrientation.PortraitUpsideDown: return DeviceDir.Vert;
            case DeviceOrientation.LandscapeLeft: return DeviceDir.Horz;
            case DeviceOrientation.LandscapeRight: return DeviceDir.Horz;            
            default: return DeviceDir.None;
        }
    }

    private void UpdateResolution()
    {
        if (mChanged > 1)
        {
            --mChanged;
        }
        else if (mChanged == 1)
        {
            OnResolutionChange();
            mChanged = 0;
        }

        var currDir = GetDeviceDir(Input.deviceOrientation);
        if (currDir != DeviceDir.None && currDir != mCurrDeviceDir)
        {
            mCurrDeviceDir = currDir;
            mChanged = kChangeDirty;
        }

        var safeArea = ScreenSafeArea;
        if (!mSafeArea.Equals(safeArea))
        {
            mSafeArea = safeArea;
            mChanged = kChangeDirty;
        }

        if (mCurrentScreenSize.x != Screen.width)
        {
            mCurrentScreenSize.x = Screen.width;
            mChanged = kChangeDirty;
        }

        if (mCurrentScreenSize.y != Screen.height)
        {
            mCurrentScreenSize.y = Screen.height;
            mChanged = kChangeDirty;
        }
    }

    private void InitResolution()
    {
        mCurrDeviceDir = Screen.width > Screen.height ? DeviceDir.Horz : DeviceDir.Vert;
        mChanged = 1;
    }

    void Update()
    {
        InitResolution();
        UpdateResolution();
    }
}