一、屏幕中各种栏目以及屏幕的尺寸
当我们需要计算屏幕中一些元素的高度时,或许需要先获取到屏幕或者各种栏目的高度,下面这个类包含了Status bar状态栏,Navigation bar虚拟按键栏,Action bar标题栏, Window屏幕内容等的宽高的计算,可以带来极大的方便。
因为我在代码中做了比较详尽的注释,在这里不再多阐述,以下是代码:
1 /** 2 * 这个类描述了当前设备的配置中system bar的尺寸(StatusBar状态栏,NavigationBar虚拟按键栏,ActionBar标题栏)、 3 * 屏幕宽高以及一些相关的特征。 4 */ 5 public static class SystemBarConfig { 6 7 private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height"; 8 private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height"; 9 private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape"; 10 private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width"; 11 private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar"; 12 13 private final int mStatusBarHeight; 14 private final int mActionBarHeight; 15 private final boolean mHasNavigationBar; 16 private final int mNavigationBarHeight; 17 private final int mNavigationBarWidth; 18 private final int mContentHeight; 19 private final int mContentWidth; 20 private final boolean mInPortrait; 21 private final float mSmallestWidthDp; 22 23 private SystemBarConfig(Activity activity) { 24 Resources res = activity.getResources(); 25 mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT); 26 mSmallestWidthDp = getSmallestWidthDp(activity); 27 mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME); 28 mActionBarHeight = getActionBarHeight(activity); 29 mNavigationBarHeight = getNavigationBarHeight(activity); 30 mNavigationBarWidth = getNavigationBarWidth(activity); 31 mContentHeight = getContentHeight(activity); 32 mContentWidth = getContentWidth(activity); 33 mHasNavigationBar = (mNavigationBarHeight > 0); 34 35 } 36 37 // 安卓系统允许修改系统的属性来控制navigation bar的显示和隐藏,此方法用来判断是否有修改过相关属性。 38 // (修改系统文件,在build.prop最后加入qemu.hw.mainkeys=1即可隐藏navigation bar) 39 // 相关属性模拟器中有使用。 40 // 当返回值等于"1"表示隐藏navigation bar,等于"0"表示显示navigation bar。 41 @TargetApi(19) 42 private String getNavBarOverride() { 43 String isNavBarOverride = null; 44 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 45 try { 46 Class c = Class.forName("android.os.SystemProperties"); 47 Method m = c.getDeclaredMethod("get", String.class); 48 m.setAccessible(true); 49 isNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys"); 50 } catch (Throwable e) { 51 isNavBarOverride = null; 52 } 53 } 54 return isNavBarOverride; 55 } 56 57 //通过此方法获取action bar的高度 58 @TargetApi(14) 59 private int getActionBarHeight(Context context) { 60 int result = 0; 61 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 62 TypedValue tv = new TypedValue(); 63 context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true); 64 result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); 65 } 66 return result; 67 } 68 69 //通过此方法获取navigation bar的高度 70 @TargetApi(14) 71 private int getNavigationBarHeight(Context context) { 72 Resources res = context.getResources(); 73 int result = 0; 74 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 75 if (hasNavBar(context)) { 76 String key; 77 if (mInPortrait) { 78 key = NAV_BAR_HEIGHT_RES_NAME; 79 } else { 80 key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME; 81 } 82 return getInternalDimensionSize(res, key); 83 } 84 } 85 return result; 86 } 87 88 //通过此方法获取navigation bar的宽度 89 @TargetApi(14) 90 private int getNavigationBarWidth(Context context) { 91 Resources res = context.getResources(); 92 int result = 0; 93 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 94 if (hasNavBar(context)) { 95 return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME); 96 } 97 } 98 return result; 99 } 100 101 //通过此方法判断是否存在navigation bar 102 @TargetApi(14) 103 private boolean hasNavBar(Context context) { 104 Resources res = context.getResources(); 105 int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android"); 106 if (resourceId != 0) { 107 boolean hasNav = res.getBoolean(resourceId); 108 // 查看是否有通过系统属性来控制navigation bar。 109 if ("1".equals(getNavBarOverride())) { 110 hasNav = false; 111 } else if ("0".equals(getNavBarOverride())) { 112 hasNav = true; 113 } 114 return hasNav; 115 } else { 116 //可通过此方法来查看设备是否存在物理按键(menu,back,home键)。 117 return !ViewConfiguration.get(context).hasPermanentMenuKey(); 118 } 119 } 120 121 //通过此方法获取资源对应的像素值 122 private int getInternalDimensionSize(Resources res, String key) { 123 int result = 0; 124 int resourceId = res.getIdentifier(key, "dimen", "android"); 125 if (resourceId > 0) { 126 result = res.getDimensionPixelSize(resourceId); 127 } 128 return result; 129 } 130 131 //通过此方法获取最小一边的dp值,再通过这个dp值大小来判断设备的navigation bar是显示在底部还是右侧 132 @TargetApi(17) 133 private float getSmallestWidthDp(Activity activity) { 134 DisplayMetrics metrics = new DisplayMetrics(); 135 float widthDp; 136 float heightDp; 137 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 138 //API 17之后使用,获取的像素宽高包含虚拟键所占空间,在API 17之前通过反射获取, 139 //获取的屏幕高度包含status bar和navigation bar 140 activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); 141 widthDp = metrics.widthPixels / metrics.density; 142 heightDp = metrics.heightPixels / metrics.density; 143 } else { 144 //获取的屏幕高度包含status bar,但不包含navigation bar 145 activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); 146 widthDp = metrics.widthPixels / metrics.density; 147 heightDp = (metrics.heightPixels + getNavigationBarWidth(activity))/ metrics.density; 148 } 149 return Math.min(widthDp, heightDp); 150 } 151 152 //通过此方法获取屏幕高度(不含status bar 和 navigation bar的高度) 153 private int getContentHeight(Activity activity) { 154 DisplayMetrics metrics = new DisplayMetrics(); 155 activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); 156 return metrics.heightPixels - getStatusBarHeight(); 157 } 158 159 //通过此方法获取屏幕的宽度(不含navigation bar的宽度) 160 private int getContentWidth(Activity activity) { 161 DisplayMetrics metrics = new DisplayMetrics(); 162 activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); 163 return metrics.widthPixels; 164 } 165 166 /** 167 * 判断navigation bar 是显示在底部还是显示在右侧 168 * 169 * @return true表示在底部,false表示在右侧 170 */ 171 public boolean isNavigationAtBottom() { 172 return (mSmallestWidthDp >= 600 || mInPortrait); 173 } 174 175 /** 176 * 获取status bar状态栏高度 177 * 178 * @return 状态栏高度的像素值 179 */ 180 public int getStatusBarHeight() { 181 return mStatusBarHeight; 182 } 183 184 /** 185 * 获取action bar的高度 186 * 187 * @return action bar高度的像素值 188 */ 189 public int getActionBarHeight() { 190 return mActionBarHeight; 191 } 192 193 /** 194 * 判断此设备是否有navigation bar虚拟按键栏 195 * 196 * @return true表示有,false表示无 197 */ 198 public boolean hasNavigtionBar() { 199 return mHasNavigationBar; 200 } 201 202 /** 203 * 获取navigation bar虚拟按键栏的高度 204 * 205 * @return 返回navigation bar虚拟按键栏的高度的像素值,如果设备没有navigation bar虚拟按键栏则返回0 206 */ 207 public int getNavigationBarHeight() { 208 return mNavigationBarHeight; 209 } 210 211 /** 212 * 获取navigation bar虚拟按键栏的宽度(当navigation bar虚拟按键栏垂直显示在右侧时使用) 213 * 214 * @return 返回navigation bar虚拟按键栏的宽度的像素值,如果设备没有navigation bar虚拟按键栏则返回0 215 */ 216 public int getNavigationBarWidth() { 217 return mNavigationBarWidth; 218 } 219 220 /** 221 * 获取屏幕高度(不含status bar 和 navigation bar的高度) 222 * 223 * @return 返回屏幕高度的像素值(不含status bar 和 navigation bar的高度) 224 */ 225 public int getContentHeight() { 226 return mContentHeight; 227 } 228 229 /** 230 * 获取屏幕宽度(不含navigation bar的宽度) 231 * 232 * @return 返回屏幕宽度的像素值(不含navigation bar的宽度) 233 */ 234 public int getContentWidth() { 235 return mContentWidth; 236 } 237 238 }
二、控制Navigation Bar的显示和隐藏
在Android4.4.2(KITKAT<Build.VERSION_CODES.KITKAT>)之前,只能设置:
1)View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
其缺点是当Touch Screen时,Navigation bar将显示出来。
从Android4.4.2起,可以设置:
1)View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
2)View.SYSTEM_UI_FLAG_IMMERSIVE
同时设置以上两个参数,即使Touch Screen时,Navigation bar也不会显示出来。
实现代码:
1 private static Handler sHandler; 2 3 protected void onCreate(Bundle savedInstanceState) { 4 super.onCreate(savedInstanceState); 5 6 sHandler = new Handler(); 7 8 sHandler.post(mHideRunnable); // hide the navigation bar 9 10 final View decorView = getWindow().getDecorView(); 11 decorView 12 .setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { 13 @Override 14 public void onSystemUiVisibilityChange(int visibility) { 15 sHandler.post(mHideRunnable); // hide the navigation bar 16 } 17 }); 18 } 19 20 Runnable mHideRunnable = new Runnable() { 21 @Override 22 public void run() { 23 int flags; 24 int curApiVersion = android.os.Build.VERSION.SDK_INT; 25 // This work only for android 4.4+ 26 if (curApiVersion >= Build.VERSION_CODES.KITKAT) { 27 // This work only for android 4.4+ 28 // hide navigation bar permanently in android activity 29 // touch the screen, the navigation bar will not show 30 flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 31 | View.SYSTEM_UI_FLAG_IMMERSIVE 32 | View.SYSTEM_UI_FLAG_FULLSCREEN; 33 34 } else { 35 // touch the screen, the navigation bar will show 36 flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 37 } 38 39 // must be executed in main thread :) 40 getWindow().getDecorView().setSystemUiVisibility(flags); 41 } 42 };
时间: 2024-10-06 03:37:29