從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