Unity刘海屏幕适配

华为适配官网网址:http://developer.huawei.com/consumer/cn/devservice/doc/50114

小米适配官网网址:https://dev.mi.com/console/doc/detail?pId=1293

Oppo适配官网网址:https://open.oppomobile.com/service/message/detail?id=61876

Vivo适配官网网址:https://dev.vivo.com.cn/doc/document/info?id=103

1、获取手机型号和手机厂商

https://blog.csdn.net/id19870510/article/details/7727046

public class ScreenAdaptation {

    public enum AndroidPhoneType {
        NONE,
        // 华为
        HuaWei,
        // 小米
        XiaoMi,
        //oppo
        OPPO,
        //vivo
        VIVO
    }

    private static String LogTag = "ScreenAdapation";
    public static final String DISPLAY_NOTCH_STATUS = "display_notch_status";

    public static void StartScreenAdapation(Context curContext) {

        Log.i(LogTag, "curContext:" + curContext);
        String phoneModel = GetManufature();
        Log.i(LogTag, "phoneModel:" + phoneModel);

        AndroidPhoneType type = GetAndroidPhoneType(phoneModel);

        switch (type) {
            case HuaWei:
                huaWeiScreenAdaptation(curContext);
                break;
            case XiaoMi:
                xiaomiScreenAdaptation(curContext);
                break;
            case OPPO:
                oppoScreenAdaptation(curContext);
                break;
            case VIVO:
                vivoScreenAdaptation(curContext);
                break;
            default:
                break;
        }
    }

    private static AndroidPhoneType GetAndroidPhoneType(String phoneModel) {
        AndroidPhoneType type = AndroidPhoneType.NONE;
        String phoneUpperModel = phoneModel.toUpperCase();

        Log.i(LogTag, "phoneUpperModel:" + phoneUpperModel);

        if (phoneUpperModel.contains("HUAWEI")) {
            type = AndroidPhoneType.HuaWei;
        } else if (phoneUpperModel.contains("XIAOMI")) {
            type = AndroidPhoneType.XiaoMi;
        } else if (phoneUpperModel.contains("OPPO")) {
            type = AndroidPhoneType.OPPO;
        } else if (phoneUpperModel.contains("VIVO")) {
            type = AndroidPhoneType.VIVO;
        }

        Log.i(LogTag, "type:" + type);
        return type;
    }

    /*获取手机型号
     */
    private static String GetModel() {
        String str = android.os.Build.MODEL;
        Log.i(LogTag, str);
        return str;
    }

    /*获取手机制造商
     */
    private static String GetManufature() {
        String str = android.os.Build.MANUFACTURER;
        Log.i(LogTag, str);
        return str;
    }
}

2、sdk manager下载Android P(API27,P preview)这个模拟器,便与测试

参考链接:https://blog.csdn.net/yi_master/article/details/80309757

如何在模拟器里面开启刘海屏设置。但是其实没什么用,没有测试后面判断刘海屏幕的代码无法执行。

3、eclipse创建一个安卓项目,发现android-support-v7-appcompat.jar里面没有AppCompatActivity.java脚本。最后放弃eclipse,更新太恶心了,更完后打开eclipse一堆sdk错误。

果断换android studio,下载快,模拟器也很方便。其实流程差不多,我重点拿华为的做例子吧,其他的就直接给代码。

1)关于华为适配:我用的是华为适配方案,感觉华为自己的方案肯定最好。而小米就直接照着写就可以了。

创建一个demo项目,创建一个ScreenAdaptation.java脚本,

   private static void huaWeiScreenAdaptation(Context curContext) {
        if (hasNotchInScreen_huawei(curContext)) {
            int[] iwh = getNotchSize_huawei(curContext);
            // 0表示“默认”,1表示“隐藏显示区域”
            int mIsNotchSwitchOpen = Settings.Secure.getInt(curContext.getContentResolver(), DISPLAY_NOTCH_STATUS, 0);
            Log.i(LogTag, iwh[0] + "|" + iwh[1] + ",mIsNotchSwitchOpen:" + mIsNotchSwitchOpen);
            UnityPlayer.UnitySendMessage("ScreenAdapation", "ScreenAdaptation", iwh[0]+"|"+iwh[1]);

        } else {
            Log.i(LogTag, "不是刘海屏幕!");
        }
    }

    /*
     * 是否是刘海屏手机: true:是刘海屏   false:非刘海屏
     */
    private static boolean hasNotchInScreen_huawei(Context context) {
        boolean ret = false;
        try {
            ClassLoader cl = context.getClassLoader();
            Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
            Object obj = get.invoke(HwNotchSizeUtil);
            Log.e(LogTag, "000:"+obj.toString());
            if(obj != null)
                ret = obj.toString().toUpperCase().equals("TRUE") ? true : false;
            Log.e(LogTag, "000:"+ret);
        } catch (ClassNotFoundException e) {
            Log.e(LogTag, "error hasNotchInScreen ClassNotFoundException");
        } catch (NoSuchMethodException e) {
            Log.e(LogTag, "error hasNotchInScreen NoSuchMethodException");
        } catch (Exception e) {
            Log.e(LogTag, "error hasNotchInScreen Exception:"+e.getMessage());
        } finally {
            return ret;
        }
    }

    /*
     * 获取刘海尺寸:width、height int[0]值为刘海宽度 int[1]值为刘海高度
     */
    private static int[] getNotchSize_huawei(Context context) {
        int[] ret = new int[]{0, 0};
        try {
            ClassLoader cl = context.getClassLoader();
            Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method get = HwNotchSizeUtil.getMethod("getNotchSize");
            ret = (int[]) get.invoke(HwNotchSizeUtil);
        } catch (ClassNotFoundException e) {
            Log.e(LogTag, "error getNotchSize ClassNotFoundException");
        } catch (NoSuchMethodException e) {
            Log.e(LogTag, "error getNotchSize NoSuchMethodException");
        } catch (Exception e) {
            Log.e(LogTag, "error getNotchSize Exception:"+e.getMessage());
        } finally {
            return ret;
        }
    }

在模拟器上面测试,由于不是华为刘海屏的硬件设备,所以测试根本看不到表现,只能看一下

2)关于测试在Testin上测试:适配后效果对比,我们做刘海屏适配的是横屏幕,只考虑这个

华为P20上面:

没做适配前:左右两边都有黑色条形图

做了适配后:界面拉伸至全屏幕

3)问题:的确做了效果和华为官方一样,但是testin上面是没有刘海区域的,在真机上面可以发现红色区域按钮被刘海屏幕遮挡了。看了一下王者荣耀其他的游戏解决方案,他们改了UI界面,由于上限测试时间有限,为了统一处理,我们想把所有UI界面统一右移动处理。当然其他的游戏可以根据自己的游戏来一套解决方案,将刘海屏幕的区域改设计啥的。

思路: 在android项目的java代码里面:判断手机类型->判断是否是刘海屏幕(根据官网网址)->是的话,发送UnitySendMessage,告知刘海区域尺寸->untiyc#代码处理

要考虑屏幕翻转

UI如何右移动:设置camera的ViewportRect的x数值

UI如何左移动:设置camera的ViewportRect的w数值

在游戏里面创建一个UICamera:所有UI都有它控制。

然后每个面板创建的时候,公司的游戏有统一处理函数,只要创建的时候给UICanvas,设置上UICamera就可以了。

相关代码:

关于设置右移动的相关代码:自己根据需求改,这个主要是测试的,屏幕尺寸自己可以得到,刘海屏尺寸传过来的自己解析:

CheckSwitchScreen.cs脚本代码如下:

using UnityEngine;
using System.Collections;

public class CheckSwitchScreen : MonoBehaviour {

    public float OffsetX = 80f;

    bool liuHai = false;
    ScreenOrientation screenOrientationKind = ScreenOrientation.Unknown;
    Rect rect;
    float offsetRate = 0f;

    static bool extra = false;
    void Awake() {
        if (extra) Destroy(gameObject);
        else {
            extra = true;            
            DontDestroyOnLoad(gameObject);
        }
    }

    //void OnEnable() {
    //    ScreenAdaptation();
    //}

    void ScreenAdaptation(string size) {
        Debug.Log("ScreenAdaptation:" + Screen.orientation);
	Debug.Log("size:" + size);
	offsetRate = OffsetX / 2280f;
        liuHai = true;
        screenOrientationKind = Screen.orientation;
        //初始化一次
        InitView();
    }

    void InitView() {
        // home 在右边
        if (screenOrientationKind == ScreenOrientation.LandscapeLeft) {
            var uiCamera = GameMain.sharedInstance.uiCamera;
            if (uiCamera != null)
                uiCamera.rect = new Rect(offsetRate, 0, 1, 1f);
        } else if (screenOrientationKind == ScreenOrientation.LandscapeRight) {
            var uiCamera = GameMain.sharedInstance.uiCamera;
            if (uiCamera != null)
                uiCamera.rect = new Rect(0, 0, 1 - offsetRate, 1f);
        }
    }

    void Update() {
        if (liuHai && screenOrientationKind != Screen.orientation) {
            screenOrientationKind = Screen.orientation;
            InitView();
        }
    }
}

4.关于小米,vivo,oppo手机的处理:

private static void xiaomiScreenAdaptation(Context context) {
        if (hasNotchInScreen_Xiaomi(context)) {
            int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
            if (resourceId > 0) {
                int result = context.getResources().getDimensionPixelSize(resourceId);
                Log.e(LogTag, "xiaomiScreenAdaptation:" + result);
                UnityPlayer.UnitySendMessage("ScreenAdapation", "ScreenAdaptation", "");
            }
            Log.e(LogTag, "00000:" + resourceId);
        } else {
            Log.e(LogTag, "222222222");
        }
    }

    private static boolean hasNotchInScreen_Xiaomi(Context context) {
        boolean result = false;
        try {
            ClassLoader cl = context.getClassLoader();
            Class systemPro = cl.loadClass("android.os.SystemProperties");
            Method get = systemPro.getMethod("get", String.class);
            Object obj = (get.invoke(systemPro, "ro.miui.notch"));
            if(obj != null)
                result = (String) obj == "1" ? true : false;
            Log.e(LogTag, "curResult:"+result);
        } catch (ClassNotFoundException e) {
            Log.e(LogTag, "error hasNotchInScreen_Xiaomi ClassNotFoundException");
        } catch (NoSuchMethodException e) {
            Log.e(LogTag, "error hasNotchInScreen_Xiaomi NoSuchMethodException");
        } catch (Exception e) {
            Log.e(LogTag, "error hasNotchInScreen_Xiaomi Exception:" + e.getMessage());
        } finally {
            return result;
        }
    }

    private static void oppoScreenAdaptation(Context context) {    	
         
        if(context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism")) {
            Log.i(LogTag, "oppoScreenAdaptation true");
            UnityPlayer.UnitySendMessage("ScreenAdapation", "ScreenAdaptation", "");
        }else{
            Log.i(LogTag, "oppoScreenAdaptation false");
        }
    }

    private static void vivoScreenAdaptation(Context context) {
        if(hasNotchInScreen_Vivo(context)){
            Log.e(LogTag, "vivoScreenAdaptation true");         
        }
            else{
            Log.e(LogTag, "vivoScreenAdaptation false");
        }
    }
    private static final int NOTCH_IN_SCREEN_VOIO=0x00000020;//是否有凹槽
    private static final int ROUNDED_IN_SCREEN_VOIO=0x00000008;//是否有圆角
    private static boolean hasNotchInScreen_Vivo(Context context){
        boolean ret = false;
        try {
            ClassLoader cl = context.getClassLoader();
            Class FtFeature = cl.loadClass("android.util.FtFeature");
            Method get = FtFeature.getMethod("isFeatureSupport",int.class);
            Object obj = get.invoke(FtFeature,NOTCH_IN_SCREEN_VOIO);
            Log.e(LogTag, "000:"+obj.toString());
            if(obj != null)
                ret = obj.toString().toUpperCase().equals("TRUE") ? true : false;
            else {
                Log.e(LogTag, "obj is null!");
            }
        } catch (ClassNotFoundException e){
            Log.e(LogTag, "hasNotchInScreen ClassNotFoundException");
        }
        catch (NoSuchMethodException e){
            Log.e(LogTag, "hasNotchInScreen NoSuchMethodException");
        }
        catch (Exception e){
            Log.e(LogTag, "hasNotchInScreen Exception");
        }
        finally{
            return ret;}
    }

除了华为给力,给了相关的尺寸的API,其他的自己根据查到的尺寸设置吧。

公司没有真机,这些都是一点一点试验出来的,有问题希望大家多多指点。
 

猜你喜欢

转载自blog.csdn.net/xj1009420846/article/details/80731855