unity 劉海全面屏適配

從2017年iPhoneX面世,到今天爲止,當前主流的手機基本上都已經是劉海屏或打孔屏,更大的屏佔比帶來更好的視覺體驗,因此對遊戲而言,適配全面屏是必不可少的。

1:打開全面屏開關

Android:默認全面屏是關閉的

在AndroidManifest.xml中添加meta-data屬性

<meta-data android:name="android.max_aspect" android:value="2.4" />

<meta-data android:name="android.notch_support" android:value="true"/>

<meta-data android:name="notch.config" android:value="portrait|landscape"/>

開啓全面屏

備註:

不知道AndroidManifest.xml文件的可以從Unity編輯器的安裝目錄

“Editor\Data\PlaybackEngines\AndroidPlayer\Apk”

拷貝一份到工程的“Assets\Plugins\Android下”在此基礎上修改

iOS: 默認全面屏是開啓的

2:適配UI

2.1:獲取劉海尺寸

我們只需要的到兩個信息:1:是否是劉海屏 2:劉海的高度

Android:

1:AndroidP也就是Android9及以上版本,Google統一支持了全面屏的API

public class NotchAndroidP extends NotchBase {

    public NotchAndroidP(Context context)
    {
        super(context);
    }

    protected void Init()
    {
        getNotchInfo();
    }

    @TargetApi(28)
    protected void getNotchInfo() {
        final View decorView = ((Activity)_context).getWindow().getDecorView();
        decorView.post(new Runnable() {
            @Override
            public void run() {
                DisplayCutout displayCutout = decorView.getRootWindowInsets().getDisplayCutout();
                if (displayCutout != null)
                {
                    _hasNotch = true;
                    _notchHeight = displayCutout.getSafeInsetTop();
                }
                _isInit = true;
            }
        });
    }

    @TargetApi(28)
    public  void DisplayFullScreen()
    {
        Window window = ((Activity)_context).getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        WindowManager.LayoutParams lp = window.getAttributes();
        lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
        window.setAttributes(lp);
    }

}

 

2:AndroidP以下每個手機廠商都定義了自己的API,來獲取劉海信息

需要判斷手機廠商然後根據類型分別處理:

    private static NotchType getNotchType()
    {
        int OSVersion = Build.VERSION.SDK_INT;
        if (OSVersion >= 28)
        {
            return NotchType.AndroidP;
        }
        String manufacturer = Build.MANUFACTURER.toUpperCase();
        Log.i("Notch", "phoneUpperModel:" + manufacturer);
        if (manufacturer.contains("HUAWEI")) {
            return NotchType.HuaWei;
        }
        if (manufacturer.contains("XIAOMI")) {
            return  NotchType.XiaoMi;
        }
        if (manufacturer.contains("OPPO")) {
            return  NotchType.OPPO;
        }
        if (manufacturer.contains("VIVO")){
            return NotchType.VIVO;
        }
        return NotchType.NONE;
    }

華爲:

public class NotchHuaWei extends NotchBase {

    public NotchHuaWei(Context context)
    {
        super(context);
    }

    protected void Init()
    {
        try {
            ClassLoader cl = _context.getClassLoader();
            Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method method = HwNotchSizeUtil.getMethod("hasNotchInScreen");
            _hasNotch = (boolean) method.invoke(HwNotchSizeUtil);
            if (_hasNotch)
            {
                method = HwNotchSizeUtil.getMethod("getNotchSize");
                int[] size = (int[]) method.invoke(HwNotchSizeUtil);
                if (size != null && size.length == 2)
                {
                    _notchHeight = size[1];
                }
            }
        }
        catch (Exception e) {
            Log.e("Notch", e.toString());
        }
        _isInit = true;
    }
}

小米:

public class NotchXiaoMi extends NotchBase {

    public NotchXiaoMi(Context context)
    {
        super(context);
    }

    protected void Init()
    {
        try {
            ClassLoader cl = _context.getClassLoader();
            Class SystemProperties = cl.loadClass("android.os.SystemProperties");
            Method method = SystemProperties.getMethod("get", String.class);
            String strNotch = (String)(method.invoke(SystemProperties, "ro.miui.notch"));
            _hasNotch = strNotch.compareTo("1") == 0;
            if (_hasNotch)
            {
                int resourceId = _context.getResources().getIdentifier("notch_height", "dimen", "android");
                if (resourceId > 0) {
                    _notchHeight = _context.getResources().getDimensionPixelSize(resourceId);
                }
            }
        } catch (Exception e) {
            Log.e("Notch", e.toString());
        }
        _isInit = true;
    }
}

官方文檔:文檔中心

OPPO:

public class NotchOppo extends NotchBase {

    public NotchOppo(Context context)
    {
        super(context);
    }

    protected void Init()
    {
        PackageManager pm = _context.getPackageManager();
        _hasNotch = pm.hasSystemFeature("com.oppo.feature.screen.heteromorphism");
        if (_hasNotch)
        {
            _notchHeight = 80;
        }
        _isInit = true;
    }
}

官方文檔:OPPO開放平臺

VIVO:

public class NotchVivo extends NotchBase {

    public static final int VIVO_NOTCH = 0x00000020;    //是否有劉海
    public static final int VIVO_FILLET = 0x00000008;   //是否有圓角

    public NotchVivo(Context context)
    {
        super(context);
    }

    protected void Init()
    {
        try {
            ClassLoader cl = _context.getClassLoader();
            Class FtFeature = cl.loadClass("android.util.FtFeature");
            Method method = FtFeature.getMethod("isFeatureSupport", int.class);
            _hasNotch = (boolean) method.invoke(FtFeature, VIVO_NOTCH);
            if (_hasNotch)
            {
                _notchHeight = 32;
            }
        } catch (Exception e) {
            Log.e("Notch", e.toString());
        }
        _isInit = true;
    }
}

官方文檔:https://swsdl.vivo.com.cn/appstore/developer/uploadfile/20180328/20180328152252602.pdf

整個Java代碼打包成jar導出給Unity使用

    private IEnumerator InitNotchAndroid()
    {
        AndroidJavaClass notchUtilsClass = new AndroidJavaClass("com.utils.notch.NotchUtils");
        if(notchUtilsClass != null)
        {
            AndroidJavaClass unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject currentActivity = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
            notchUtilsClass.CallStatic("init", new object[] { currentActivity });
            bool isInitDone = false;
            while(!isInitDone)
            {
                isInitDone = notchUtilsClass.CallStatic<bool>("isInitDone");
                yield return null;
            }
            _hasNotch = notchUtilsClass.CallStatic<bool>("hasNotch");
            if(_hasNotch)
            {
                _notchSize = notchUtilsClass.CallStatic<int>("getNotchHeight");
            }
        }
        yield return null;
    }

iOS:

採用Unity自帶的函數 Screen.safeArea,在橫屏下其中的X值就代表劉海的高度,Unity版本使用的是2017

    private IEnumerator InitNotchiOS()
    {
        float notchSize = Screen.safeArea.x;
        if (notchSize > 0.0f)
        {
            _hasNotch = true;
            _notchSize = notchSize;
        }
        yield return null;
    }

2.2 設置UI偏移

這裏採用UGUI來實現UI,以下都以橫屏遊戲爲例

在UGUI中通過Anchor來設置RectTransform的矩形範圍

anchorMin:設置xmin,ymin,相對父節點的百分比

anchorMax:設置xmax,ymax,相對父節點的百分比

例如:

anchorMin:(0,0)

anchorMax:(1,1)

這代表與父節點大小一樣大

我們一般在Canvas節點下建立一個空的RectTransform節點,設置其Anchor,使其與父節點一樣大,也就是屏幕的大小

獲取劉海的高度後,除以屏幕的寬度得到百分比,然後設置anchorMin.x

anchorMin.x = 劉海的高度 / Screen.width

整個UI的矩形範圍左側就會縮進

在iPhone11模擬器上測試:

 

轉載自:https://zhuanlan.zhihu.com/p/126699544

發佈於 2020-04-09

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章