1全面屏dialog 弹窗问题
注意dialog布局不要设置 背景颜色
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@color/transparent</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>
2 底部虚拟按键问题
自全面屏出来以后判断虚拟按键是否隐藏的常用方法不管用了,无论是否隐藏都会返回true,比如以下常用的两种检查虚拟按键是否存在的方法:
public static boolean checkDeviceHasNavigationBar() {
boolean hasNav = false;
// 通过WindowManagerGlobal 获取WindowManagerService 反射WindowManagerGlobal.getWindowManagerService();
try {
Class<?> windowManagerGlobalClass = Class.forName("android.view.WindowManagerGlobal");
// 获取WindowManagerGlobal 中的私有方法
Method getWindowManagerService = windowManagerGlobalClass.getDeclaredMethod("getWindowManagerService");
getWindowManagerService.setAccessible(true);
//getWindowManagerService 是静态方法
Object iwindowManager = getWindowManagerService.invoke(null);
// 获取windowManagerService 的hasNavigationBar 方法的返回值
Class<?> aClass = iwindowManager.getClass();
Method hasNavigationBar = aClass.getDeclaredMethod("hasNavigationBar");
hasNavigationBar.setAccessible(true);
hasNav = (boolean) hasNavigationBar.invoke(iwindowManager);
} catch (Exception e) {
e.printStackTrace();
}
return hasNav;
}
//判断是否存在NavigationBar
public static boolean hasNavigationBar(Context context) {
boolean hasNavigationBar = false;
Resources rs = context.getResources();
int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
if (id > 0) {
hasNavigationBar = rs.getBoolean(id);
}
try {
//反射获取SystemProperties类,并调用它的get方法
Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
Method m = systemPropertiesClass.getMethod("get", String.class);
String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
if ("1".equals(navBarOverride)) {
hasNavigationBar = false;
} else if ("0".equals(navBarOverride)) {
hasNavigationBar = true;
}
} catch (Exception e) {
e.printStackTrace();
}
return hasNavigationBar;
}
在华为、小米等全面屏手机上,当虚拟按键隐藏时获取的,调用以上两种方法返回的都是true ,也就是说虚拟按键并没有被真正的隐藏。
解决方案
关于全面屏手机虚拟导航键的开关
由于全面屏手机都没有底部的Home,Back等实体按键,因此,大多数全面屏手机都是支持虚拟导航键,即通过上面的方法hasNavigationBar获取的返回值都是true。
当隐藏虚拟导航键时,用户可以通过底部上滑的手势实现导航键同样的功能,非常便利。
但对我们开发者来说这是很蛋疼的问题。在一些全面屏手机上,仅仅通过上面给出的hasNavigationBar是无法准确判断NavigationBar存在与否的,hasNavigationBar这个方法一直都是返回true。并且获取到的虚拟按键的高度一直是130.
解决办法必须得有,那就是获取==setting==中收拾开关的值。代码如下:
public static boolean navigationGestureEnabled(Context context) {
int val = Settings.Secure.getInt(context.getContentResolver(), NAVIGATION_GESTURE, NAVIGATION_GESTURE_OFF);
return val != NAVIGATION_GESTURE_OFF;
}
最后,判断当前系统是否存在并开启了NavigationBar,就要结合上面给出的两个方法一起判断才准确:
//navigationGestureEnabled()从设置中取不到值的话,返回false,因此也不会影响在其他手机上的判断
public static boolean realHasNavigationBar(Context context) {
return hasNavigationBar(context) && !navigationGestureEnabled(context);
}
但是在小米和华为的全面屏手机虚拟按键一直存在,找不到获取全面屏的开关 查了半天资料无解。。。。
获取虚拟按键的高度
/**
* 获取虚拟功能键高度
*
* @param context
*
* @return
*/
public static int getNavigationBarHeight(Activity activity) {
if (!isNavigationBarShow(activity)) {
return 0;
}
Resources resources = activity.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height",
"dimen", "android");
//获取NavigationBar的高度
int height = resources.getDimensionPixelSize(resourceId);
return height;
}
显示隐藏虚拟按键
1、只使用SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN
这种情况下,在进入全屏模式后,用户有任何操作,SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN就会被清除。状态栏和虚拟按键会一直可见。除非再次设置SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN。在状态栏和虚拟按键显示变化时会调用View.OnSystemUiVisibilityChangeListener。
2、SYSTEM_UI_FLAG_IMMERSIVE配合SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN使用
用户操作不会清除SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN,会一直保持全屏模式。显示切换时也会触发View.OnSystemUiVisibilityChangeListener。还有一个区别就是,全屏模式时,从原本状态栏或者虚拟按键的位置响屏幕内部滑动,会清除SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN,保持可见状态,并且也会触发OnSystemUiVisibilityChangeListener监听。
3、SYSTEM_UI_FLAG_IMMERSIVE_STICKY配合SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN使用
用户操作不会清除SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN。会一直保持全屏模式。显示切换时也会触发View.OnSystemUiVisibilityChangeListener,全屏模式时,从原本状态栏或者虚拟按键的位置 响屏幕内部滑动,状态栏和虚拟按键栏会暂时可见,一段时间后自动隐藏。与SYSTEM_UI_FLAG_IMMERSIVE不同的是,因为是临时的显示,所以不会触发OnSystemUiVisibilityChangeListener。
public void hideNavigationBar(Activity activity) {
int uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
int newUiOptions = uiOptions;
boolean isImmersiveModeEnabled =
((uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) == uiOptions);
if (!isImmersiveModeEnabled) {
if (Build.VERSION.SDK_INT >= 14) {
newUiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
}
if (Build.VERSION.SDK_INT >= 16) {
newUiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
}
if (Build.VERSION.SDK_INT >= 18) {
newUiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
activity.getWindow().getDecorView().setSystemUiVisibility(newUiOptions);
}
}
显示虚拟按键
public void showNavigationBar(Activity context) {
int uiOptions = context.getWindow().getDecorView().getSystemUiVisibility();
int newUiOptions = uiOptions;
boolean isImmersiveModeEnabled =
((uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) == uiOptions);
if (isImmersiveModeEnabled) {
//先取 非 后再 与, 把对应位置的1 置成0,原本为0的还是0
if (Build.VERSION.SDK_INT >= 14) {
newUiOptions &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
}
if (Build.VERSION.SDK_INT >= 16) {
newUiOptions &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
}
if (Build.VERSION.SDK_INT >= 18) {
newUiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
context.getWindow().getDecorView().setSystemUiVisibility(newUiOptions);
}
}
监听虚拟按键的显示和隐藏
final View content = getActivity().getWindow().getDecorView().findViewById(android.R.id.content);
content.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//屏幕发生改变
int height = content.getHeight();
params.height = (height - (ViewMeasureUtils.getHeight(itemView)));//获取DecorView content的高度减去视频的高度,这样可以适配全面屏
}
});










网友评论