手机屏幕适配
2021-03-15 本文已影响0人
crossroads
前言
公司有很多要根据样式自动改变位置的需求,安卓机型各种各样,适配起来就是一个坑啊,今天把大致的坑填一下,供大家参考。
一坑:底部导航栏
一般手机我们会用这样的方法来判断有无导航栏
/**
* @return 是否存在虚拟按键栏
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public static boolean hasNavBar(Context context) {
Resources res = context.getResources();
int resourceId = res.getIdentifier("config_showNavigationBar", "bool", "android");
if (resourceId != 0) {
boolean hasNav = res.getBoolean(resourceId);
String sNavBarOverride = getNavBarOverride();
if ("1".equals(sNavBarOverride)) {
hasNav = false;
} else if ("0".equals(sNavBarOverride)) {
hasNav = true;
}
return hasNav;
} else {
return !ViewConfiguration.get(context).hasPermanentMenuKey();
}
}
/**
* 判断虚拟按键栏是否重写
*/
private static String getNavBarOverride() {
String sNavBarOverride = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Class c = Class.forName("android.os.SystemProperties");
Method m = c.getDeclaredMethod("get", String.class);
m.setAccessible(true);
sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
} catch (Exception e) {
TRTCLogTools.e(TAG, e.toString());
}
}
return sNavBarOverride;
}
然而,会发现华为、小米、vivo不管有没有隐藏底部导航栏,它都返回true!所以只能针对这几个机型进行机型适配了。
- 首先判断手机机型
/**
* 获取手机品牌
*/
public static String getDeviceManufacturer() {
return android.os.Build.MANUFACTURER;
}
public static boolean isHuawei() {
if ("HUAWEI".equalsIgnoreCase(getDeviceManufacturer())) {
return true;
}
return false;
}
- 根据不同手机判断有无底部导航栏
public static boolean isXiaoMiNavigationBarShow(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (Settings.Global.getInt(context.getContentResolver(), "force_fsg_nav_bar", 0) != 0) {
//开启手势,不显示虚拟键
return false;
}
}
return true;
}
public static boolean isHuaWeiNavigationBarShow(Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return Settings.System.getInt(context.getContentResolver(), "navigationbar_is_min", 0) == 0;
} else {
return Settings.Global.getInt(context.getContentResolver(), "navigationbar_is_min", 0) == 0;
}
}
public static boolean isVivoNavigationBarShow(Context context) {
return Settings.Secure.getInt(context.getContentResolver(), "navigation_gesture_on", 0) == 0;
}
至此就可以判断是否有导航栏了。接下来,就可以获取导航栏高度了
/**
* 获取虚拟按键的高度
*/
public static int getNavigationBarHeight(Context context) {
int result = 0;
if (hasNavBar(context)
&& (!isMIUI() || isXiaoMiNavigationBarShow(context))
&& (!isVivo() || isVivoNavigationBarShow(context))
&& (!isHuawei() || isHuaWeiNavigationBarShow(context))) {
Resources res = context.getResources();
int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = res.getDimensionPixelSize(resourceId);
}
}
return result;
}
二坑:弹窗
场景:当做直播的时候,通常需要直播页面充满全屏,也就是要做沉浸式。这时,我们要设置页面全屏,使用android:windowTranslucentNavigation设置透明导航栏,然后发现有些手机show底部弹窗dialog底部永远在导航栏上方,而我们的activity的布局底部是在导航栏下方
灰色是activity底部,红色是弹窗底部
为了统一在导航栏上方,这时候就需要将activity的我们需要在虚拟导航栏之上的根布局使用
android:fitsSystemWindows="true"
将布局底部也变为导航栏的上方,其实是设置了android:fitsSystemWindows="true"属性的view会自动添加一个值等于导航栏高度的paddingBottom。这样view的底部也就和dialog的底部保持一致啦。记住:不要在activity的根布局设置,因为如果你设置的话,它的顶部也不能到最上面啦。所以只要针对你想要至于导航栏之上的view的根布局就好。
三坑、手机屏幕高度
要做沉浸式,需要获取手机屏幕的真实高度,即包含导航栏这些的真正高度,要这样获取
public static int getScreenRealHeight(Context context) {
WindowManager windowManager =
(WindowManager) context.getSystemService(Context.
WINDOW_SERVICE);
final Display display = windowManager.getDefaultDisplay();
Point outPoint = new Point();
if (Build.VERSION.SDK_INT >= 19) {
// 可能有虚拟按键的情况
display.getRealSize(outPoint);
} else {
// 不可能有虚拟按键
display.getSize(outPoint);
}
return outPoint.y;
}