从2017年iPhoneX面世,到今天为止,当前主流的手机基本上都已经是刘海屏或打孔屏,更大的屏占比带来更好的视觉体验,因此对游戏而言,适配全面屏是必不可少的。
1:打开全面屏开关
Android:默认全面屏是关闭的
在AndroidManifest.xml中添加meta-data属性
开启全面屏
备注:
不知道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("currentActivity");
notchUtilsClass.CallStatic("init", new object[] { currentActivity });
bool isInitDone = false;
while(!isInitDone)
{
isInitDone = notchUtilsClass.CallStatic("isInitDone");
yield return null;
}
_hasNotch = notchUtilsClass.CallStatic("hasNotch");
if(_hasNotch)
{
_notchSize = notchUtilsClass.CallStatic("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