劉海屏的适配
- 關于劉海屏适配問題、android跟風劉海屏、在android P(9.0 API 28)才能用原生的android 劉海屏适配、在Android N(7.0 API 24)到 android P(9.0 API 28)期間、很多廠商都對自己的硬體做了提前的适配,是以需要我們對其做适配、
- 何時才需要适配、設定全屏模式下,需要對劉海屏進行适配。不然會存在這樣的問題U展示不全問題、在android N 以下的設定全屏沒問題。在N - P 有劉海屏情況下 則會有UI顯示異常(底部ui顯示不全)。故設定一個包裹容器包裹、
- 怎麼适配呢、
- 判斷版本區間(android N 以下、android N - android P、 Android P 以上)
- android N 以下, 直接預設的設定全屏。 android N 以上 直接如果不是劉海屏 則設定為全屏,如果是劉海屏則不進行設定。
requestWindowFeature(Window.FEATURE_NO_TITLE)
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN)
複制代碼
- 不同的廠商劉海屏的适配也不同具體參考對應的開發者平台。以下代碼說明如何查詢是否是劉海屏,以及擷取劉海屏的高度。若類似于一加手機沒有開發者平台交流的、隻好單獨拎出來,判斷。
擷取到劉海屏的高度、若沒有,則傳回0
// ------------------------------ 劉海屏處理 ------------------------------
private static final String ONEPLUS6 = "ONEPLUS A6000";
/**
* 擷取劉海的高度
*
* @param context
* @return
*/
public static int obtainCutoutHeight(Context context) {
// 7.0以下不會有劉海,避免不必要的反射性能損耗
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return 0;
}
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// ------------------------------ Android P 版本 及以上 的統一适配 ------------------------------
val displayCutout: DisplayCutout? = rootWindowInsets.displayCutout
if (displayCutout != null) {
L.e("TAG", "安全區域距離螢幕頂部的距離 SafeInsetTop:" + displayCutout.safeInsetTop)
return displayCutout.safeInsetTop
}
return 0
}*/
if (OSUtils.isEMUI() && OSUtils.hasHWNotchInScreen(context)) {
return OSUtils.getHWNotchSize(context)[1];
}
if (OSUtils.isMIUI() && OSUtils.hasMIUINotchInScreen()) {
return OSUtils.getMIUINotchSize(context);
}
// oppo固定80px
if (OSUtils.hasOppoNotchInScreen(context)) {
return 80;
}
if (OSUtils.hasVivoNotchInScreen(context)) {
return obtainStatusBarHeight(context);
}
if (ONEPLUS6.equals(Build.MODEL)) {
return obtainStatusBarHeight(context);
}
return 0;
}
public static int obtainStatusBarHeight(Context context) {
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
int statusBarHeight = 0;
if (resourceId > 0) {
statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
}
return statusBarHeight;
}
複制代碼
判斷是不是華為
/**
* 判斷是否為emui
* Is emui boolean.
*
* @return the boolean
*/
public static boolean isEMUI() {
String property = getSystemProperty(KEY_EMUI_VERSION_NAME, "");
return !TextUtils.isEmpty(property);
}
複制代碼
華為是否有劉海屏
activity 标簽下添加
<meta-data android:name="android.notch_support" android:value="true"/>
複制代碼
/**
* 判斷是否是華為劉海屏
*
* @param context
* @return
*/
public static boolean hasHWNotchInScreen(Context context) {
boolean hasNotch = false;
try {
ClassLoader classLoader = context.getClassLoader();
Class hwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method method = hwNotchSizeUtil.getMethod("hasNotchInScreen");
hasNotch = (Boolean) method.invoke(hwNotchSizeUtil);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return hasNotch;
}
複制代碼
擷取華為劉海屏高度
/**
* 擷取華為劉海的高寬
*
* @param context 上下文對象
* @return [0]值為劉海寬度int;[1]值為劉海高度
*/
public static int[] getHWNotchSize(Context context) {
int[] size = new int[2];
try {
ClassLoader classLoader = context.getClassLoader();
Class hwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method method = hwNotchSizeUtil.getMethod("getNotchSize");
size = (int[]) method.invoke(hwNotchSizeUtil);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return size;
}
複制代碼
MIUI 是否有劉海屏、及劉海屏的高度
/**
* 判斷是否為miui
* Is miui boolean.
*
* @return the boolean
*/
public static boolean isMIUI() {
String property = getSystemProperty(KEY_MIUI_VERSION_NAME, "");
return !TextUtils.isEmpty(property);
}
/**
* 隻适用于判斷MIUI 是否有劉海屏
* SystemProperties.getInt("ro.miui.notch", 0) == 1;
*
* @return
*/
public static boolean hasMIUINotchInScreen() {
try {
Class<?> clz = Class.forName("android.os.SystemProperties");
Method get = clz.getMethod("getInt", String.class, String.class);
return (int) get.invoke(clz, "ro.miui.notch", -1) == 1;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 擷取MIUI 的劉海屏高度
*
* @param context
*/
public static int getMIUINotchSize(Context context) {
int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android");
if (resourceId > 0) {
return context.getResources().getDimensionPixelSize(resourceId);
}
return 0;
}
複制代碼
oppo 是否有劉海屏、并統一設定為80px
/**
* 是否是Oppo的劉海屏
*
* @param context
* @return
*/
public static boolean hasOppoNotchInScreen(Context context) {
return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
}
複制代碼
vivo 是否支援劉海屏、 并設定高度為狀态欄高度
/**
* Vivo手機劉海屏
*
* @param context
* @return
*/
/**
* 是否有劉海
*/
public static final int VIVO_NOTCH = 0x00000020;
/**
* 是否有圓角
*/
public static final int VIVO_FILLET = 0x00000008;
public static boolean hasVivoNotchInScreen(Context context) {
boolean ret = false;
try {
ClassLoader classLoader = context.getClassLoader();
Class FtFeature = classLoader.loadClass("android.util.FtFeature");
Method method = FtFeature.getMethod("isFeatureSupport", int.class);
ret = (boolean) method.invoke(FtFeature, VIVO_NOTCH);
} catch (ClassNotFoundException e) {
Log.e("Notch", "hasNotchAtVoio ClassNotFoundException");
} catch (NoSuchMethodException e) {
Log.e("Notch", "hasNotchAtVoio NoSuchMethodException");
} catch (Exception e) {
Log.e("Notch", "hasNotchAtVoio Exception");
} finally {
return ret;
}
}
複制代碼
自定義包裹的LinearLayout
/**
* @author:Created by Mrko
* @description: 劉海屏适配類
*/
class DisplayCutoutView : LinearLayout {
private lateinit var emptyView: View
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initView()
}
fun initView() {
val viewParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
StatusBarUtils.obtainCutoutHeight(context))
emptyView = View(context)
emptyView.layoutParams = viewParams
addView(emptyView)
}
}
複制代碼
運用地方
<com.xxx.DisplayCutoutView
android:id="@+id/rl_display"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/primary_pressed"
android:orientation="vertical">
<com.xxx.hintView
android:id="@+id/color_detail_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp" />
</com.xxx.DisplayCutoutView>
複制代碼
Activity 進行相容性适配
override fun beforeSetContentView() {
/*L.e("mrko--->", "手機品牌--> \n ${Build.PRODUCT} + \n
"${Build.DEVICE} + \n
"${Build.BOARD} + \n
"${Build.MANUFACTURER} + \n
"${Build.BRAND} + \n
"${Build.MODEL} + \n
"${Build.HARDWARE} + \n
"${Build.MANUFACTURER} + \n
"${Build.ID} + \n
"${Build.DISPLAY} + \n ")*/
if (StatusBarUtils.obtainCutoutHeight(mContext) == 0) {
requestWindowFeature(Window.FEATURE_NO_TITLE)
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN)
}
super.beforeSetContentView()
}
複制代碼
附上參考連結 juejin.im/post/5b1930…
轉載于:https://juejin.im/post/5b7c01a6f265da43445f5e8d