Unity Android 刘海屏适配原理

在 Unity 中开发 Android 应用时,处理刘海屏(Notch)设备是一个需要注意的细节。刘海屏设备在屏幕顶部有一个凹口,用于放置摄像头、传感器等硬件组件。为了确保应用在这些设备上有良好的用户体验,需要正确处理刘海屏区域。

安卓刘海屏、水滴屏等在谷歌官方文档中统一命名为缺口屏(Notch Screen)。要获取Android手机刘海屏的信息,需要在JAVA层调用android的API。Google从Android P(API 28)开始提供了官方API,用于获取缺口屏信息。对于安装了Android P之前版本系统的手机,就没有Google官方API帮助我们了。不过,华为、小米、OPPO、VIVO、三星等手机厂商在自家定制系统中提供了自己的API,我们可以通过反射的方式调用这些API来获取缺口屏信息。

在Unity中实现Android缺口屏适配的思路是

1)获取当前手机是否为缺口平;
2)获取缺口屏缺口尺寸;
3)让游戏渲染进缺口区域;
4)位移游戏中的UI元素,防止刘海区域遮挡UI

下面将会详细讲解以原生和unity两种实现方式

原生

在 Unity 中使用 Android 底层 API 接口来实现缺口屏(刘海屏)适配,可以通过调用 Android 的原生代码来获取设备的缺口信息。以下是详细的实现步骤和代码示例:

1. 获取当前手机是否为缺口屏

通过调用 Android 的原生 API,可以获取设备是否为缺口屏。

2. 获取缺口屏缺口尺寸

通过 Android 的原生 API 获取缺口屏的缺口尺寸。

3. 让游戏渲染进缺口区域

确保游戏在全屏模式下运行,并且允许渲染到缺口区域。

4. 位移游戏中的 UI 元素,防止刘海区域遮挡 UI

使用 Screen.safeArea 动态调整 UI 元素的位置和大小,确保它们不会被刘海遮挡。

实现步骤和代码示例

1. 创建 Android 原生插件

首先,需要创建一个 Android 原生插件来获取缺口屏信息。

  1. 在 Unity 项目中创建一个 Plugins/Android 文件夹。
  2. Plugins/Android 文件夹中创建一个新的 Android Studio 项目,或者直接创建一个 Java 文件。

以下是一个示例 Java 文件 NotchUtils.java

package com.yourcompany.notchutils;

import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.view.DisplayCutout;
import android.view.WindowInsets;

public class NotchUtils {

    public static boolean hasNotch(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            WindowInsets windowInsets = activity.getWindow().getDecorView().getRootWindowInsets();
            if (windowInsets != null) {
                DisplayCutout displayCutout = windowInsets.getDisplayCutout();
                return displayCutout != null;
            }
        }
        return false;
    }

    public static Rect getNotchSize(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            WindowInsets windowInsets = activity.getWindow().getDecorView().getRootWindowInsets();
            if (windowInsets != null) {
                DisplayCutout displayCutout = windowInsets.getDisplayCutout();
                if (displayCutout != null) {
                    Rect safeInsetRect = new Rect(
                        displayCutout.getSafeInsetLeft(),
                        displayCutout.getSafeInsetTop(),
                        displayCutout.getSafeInsetRight(),
                        displayCutout.getSafeInsetBottom()
                    );
                    return safeInsetRect;
                }
            }
        }
        return new Rect(0, 0, 0, 0);
    }
}

编译这个 Java 文件并生成 .jar 文件,然后将其放入 Plugins/Android 文件夹中。

2. 在 Unity 中调用 Android 原生插件

在 Unity 中编写一个 C# 脚本来调用 Android 原生插件。

using UnityEngine;
using System.Runtime.InteropServices;

public class NotchScreenHandler : MonoBehaviour
{
    private AndroidJavaObject activity;
    private AndroidJavaClass notchUtils;

    void Start()
    {
        if (Application.platform == RuntimePlatform.Android)
        {
            using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
            {
                activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
            }

            notchUtils = new AndroidJavaClass("com.yourcompany.notchutils.NotchUtils");

            bool hasNotch = notchUtils.CallStatic<bool>("hasNotch", activity);
            if (hasNotch)
            {
                Rect notchSize = GetNotchSize();
                Debug.Log("Notch Size: " + notchSize);
                // Adjust UI elements based on notch size
                AdjustUIForNotch(notchSize);
            }
        }
    }

    Rect GetNotchSize()
    {
        AndroidJavaObject rect = notchUtils.CallStatic<AndroidJavaObject>("getNotchSize", activity);
        int left = rect.Get<int>("left");
        int top = rect.Get<int>("top");
        int right = rect.Get<int>("right");
        int bottom = rect.Get<int>("bottom");
        return new Rect(left, top, right - left, bottom - top);
    }

    void AdjustUIForNotch(Rect notchSize)
    {
        // Implement your UI adjustment logic here
        // For example, move UI elements to avoid the notch area
    }
}

3. 确保游戏渲染进缺口区域

Player Settings 中设置全屏模式:

  • 打开 Edit > Project Settings > Player
  • Resolution and Presentation 部分,确保 Fullscreen Mode 设置为 Fullscreen WindowMaximized Window
  • 确保 Render Outside Safe Area 选项被勾选。

4. 位移游戏中的 UI 元素,防止刘海区域遮挡 UI

NotchScreenHandler 脚本中,编写逻辑来调整 UI 元素的位置和大小,确保它们不会被刘海遮挡。

using UnityEngine;
using UnityEngine.UI;

public class NotchScreenHandler : MonoBehaviour
{
    private AndroidJavaObject activity;
    private AndroidJavaClass notchUtils;

    void Start()
    {
        if (Application.platform == RuntimePlatform.Android)
        {
            using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
            {
                activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
            }

            notchUtils = new AndroidJavaClass("com.yourcompany.notchutils.NotchUtils");

            bool hasNotch = notchUtils.CallStatic<bool>("hasNotch", activity);
            if (hasNotch)
            {
                Rect notchSize = GetNotchSize();
                Debug.Log("Notch Size: " + notchSize);
                AdjustUIForNotch(notchSize);
            }
        }
    }

    Rect GetNotchSize()
    {
        AndroidJavaObject rect = notchUtils.CallStatic<AndroidJavaObject>("getNotchSize", activity);
        int left = rect.Get<int>("left");
        int top = rect.Get<int>("top");
        int right = rect.Get<int>("right");
        int bottom = rect.Get<int>("bottom");
        return new Rect(left, top, right - left, bottom - top);
    }

    void AdjustUIForNotch(Rect notchSize)
    {
        // 获取 Canvas 的 RectTransform
        RectTransform canvasRectTransform = GetComponent<RectTransform>();

        // 计算安全区域
        Rect safeArea = Screen.safeArea;

        // 将安全区域转换为 Canvas 的坐标
        Vector2 anchorMin = safeArea.position;
        Vector2 anchorMax = safeArea.position + safeArea.size;

        anchorMin.x /= Screen.width;
        anchorMin.y /= Screen.height;
        anchorMax.x /= Screen.width;
        anchorMax.y /= Screen.height;

        // 设置 Canvas 的锚点
        canvasRectTransform.anchorMin = anchorMin;
        canvasRectTransform.anchorMax = anchorMax;

        // 你可以在这里进一步调整 UI 元素的位置和大小
        // 例如,移动顶部的 UI 元素以避免被刘海遮挡
        foreach (RectTransform child in canvasRectTransform)
        {
            if (child.anchorMin.y == 1 && child.anchorMax.y == 1)
            {
                // 这是一个顶部对齐的 UI 元素
                child.anchoredPosition += new Vector2(0, -notchSize.height);
            }
        }
    }
}

unity

在 Unity 中实现 Android 缺口屏(刘海屏)适配的思路可以按照你提到的步骤进行。以下是详细的实现步骤和代码示例:

1. 获取当前手机是否为缺口屏

在 Unity 中,无法直接通过 API 获取设备是否为缺口屏,但可以通过 Screen.safeArea 属性来判断屏幕的安全区域。如果安全区域小于屏幕的全区域,则可以认为设备有刘海。

2. 获取缺口屏缺口尺寸

通过 Screen.safeArea 可以获取屏幕的安全区域,从而计算出缺口的尺寸。

3. 让游戏渲染进缺口区域

确保游戏在全屏模式下运行,并且允许渲染到缺口区域。

4. 位移游戏中的 UI 元素,防止刘海区域遮挡 UI

使用 Screen.safeArea 动态调整 UI 元素的位置和大小,确保它们不会被刘海遮挡。

实现步骤和代码示例

1. 设置全屏模式

Player Settings 中设置全屏模式:

  • 打开 Edit > Project Settings > Player
  • Resolution and Presentation 部分,勾选 Fullscreen Mode
2. 编写 SafeAreaHandler 脚本

编写一个脚本来处理安全区域,并调整 UI 元素的位置和大小。

using UnityEngine;
using UnityEngine.UI;

public class SafeAreaHandler : MonoBehaviour
{
    private RectTransform rectTransform;

    void Start()
    {
        rectTransform = GetComponent<RectTransform>();
        ApplySafeArea();
    }

    void ApplySafeArea()
    {
        Rect safeArea = Screen.safeArea;

        Vector2 anchorMin = safeArea.position;
        Vector2 anchorMax = safeArea.position + safeArea.size;

        anchorMin.x /= Screen.width;
        anchorMin.y /= Screen.height;
        anchorMax.x /= Screen.width;
        anchorMax.y /= Screen.height;

        rectTransform.anchorMin = anchorMin;
        rectTransform.anchorMax = anchorMax;
    }

    void Update()
    {
        // Optional: Continuously check and apply safe area in case of orientation changes
        ApplySafeArea();
    }
}

将此脚本附加到需要调整的 UI 元素上(如 CanvasPanel)。

3. 确保游戏渲染进缺口区域

Player Settings 中,确保以下设置:

  • 打开 Edit > Project Settings > Player
  • Resolution and Presentation 部分,确保 Render Outside Safe Area 选项被勾选。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值