Android应用:StatusBar状态栏、NavigationBar虚拟按键栏、ActionBar标题栏、Window屏幕内容区域等的宽高

一、屏幕中各种栏目以及屏幕的尺寸

当我们需要计算屏幕中一些元素的高度时,或许需要先获取到屏幕或者各种栏目的高度,下面这个类包含了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

Android应用:StatusBar状态栏、NavigationBar虚拟按键栏、ActionBar标题栏、Window屏幕内容区域等的宽高的相关文章

Android知识点:隐藏底部虚拟按键

/** * 隐藏底部虚拟按键,且全屏 */ private void hideBottomMenu() { //隐藏虚拟按键,并且全屏 if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api View v = this.getWindow().getDecorView(); v.setSystemUiVisibility(View.GONE); } else if (Build.V

Android 获取虚拟按键的高度

//获取虚拟按键的高度 public static int getNavigationBarHeight(Context context) { int result = 0; if (hasNavBar(context)) { Resources res = context.getResources(); int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "androi

Android 沉浸式状态栏

效果图 android 5.0 以上 android 4.4 API 19 以上都是原生安卓系统的效果,具体到国内的各种各样改过的系统可能会有细微差别,测试过小米和华为的机器效果基本一样. 实现 1.修改主题属性 方法一: 在values-v19文件夹下声明AppTheme为透明状态栏,代码如下 1 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> 2 <!-- C

android获取控件宽高和屏幕宽高

一.获取屏幕宽高 1.android界面简单介绍 要获取屏幕宽高,我们可以先从android的界面构成了解 android的界面主要由三部分构成:1.状态栏 2.标题栏 3.内容区域 \ (1)状态栏 状态栏主要用来显示一些系统图标,应用的通知图标和系统时间. (2)标题栏 android中标题栏主要用来显示当前位置,3.0过后添加了ActionBar,拥有了导航和OptionMenu的功能,5.0又新添加了ToolBar控件,和ActionBar类似,但自定义的空间更充足 (3)内容区域 an

Android 去除状态栏和隐藏虚拟按键

//取消状态栏getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 一定得在setContentView()上面 隐藏虚拟按键: protected void hideBottomUIMenu() { //隐藏虚拟按键,并且全屏 if (Build.VERSION.SDK_INT > 11 && Build.VERSIO

获取虚拟按键、状态栏等高度;

/获取屏幕原始尺寸高度,包括虚拟功能键高度 public static int getDpi(Context context){ int dpi = 0; WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); DisplayMetrics displayM

动态显示和隐藏状态栏(包括底部虚拟按键)

小米Launcher有一个细节上的功能效果:在长按桌面应用图标时,会隐藏状态栏,然后在状态栏原有的布局上显示卸载或删除的操作栏.放手后,操作栏隐藏,状态栏显示出来.也就是说,这个过程是涉及到对状态栏的动态操作的. View类提供了setSystemUiVisibility和getSystemUiVisibility方法,这两个方法实现对状态栏的动态显示或隐藏的操作,以及获取状态栏当前可见性. setSystemUiVisibility(int visibility)方法可传入的实参为: 1. V

android 虚拟按键是通过哪种机制上报的?

1.在normal mode下,tp button也是和其他触摸事件一样,以坐标形式的input_event进行上报.在初始化时会通过tpd_button_setting()函数依据定义在tpd_custom_XXX.h文件里的配置信息将虚拟按键的坐标信息写在/sys/board_properties/virtualkeys.mtk-tpd中. 工作时.tp driver将按下的点的坐标进行上报.Android上层会读取sys中的按键配置信息.再推断上报的坐标是否属于某个按键的坐标范围,以此将坐

隐藏Android下的虚拟按键

要隐藏Android下的虚拟按键,可通过如下办法操作 [cpp] view plain copy adb root adb remount adb shell ls -al /system/build.prop   (查看文件权限) -rw-r--r-- root     root         4237 2015-11-19 04:34 build.prop adb shell pull /system/build.prop ./  (将该文件拿出来修改) gedit  build.prop