刘海屏的适配
- 关于刘海屏适配问题、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()
}
复制代码