您的位置:首页 > 移动开发 > Android开发

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

2016-03-31 15:33 363 查看


感谢IT大道,copy只为了防止原文被删。原文请看 http://www.itdadao.com/2016/02/07/353404/


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

当我们需要计算屏幕中一些元素的高度时,或许需要先获取到屏幕或者各种栏目的高度,下面这个类包含了Status bar状态栏,Navigation bar虚拟按键栏,Action bar标题栏, Window屏幕内容等的宽高的计算,可以带来极大的方便。

因为我在代码中做了比较详尽的注释,在这里不再多阐述,以下是代码:
package com.felix.navtest;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.ViewConfiguration;

import java.lang.reflect.Method;

/**
2  * 这个类描述了当前设备的配置中system bar的尺寸(StatusBar状态栏,NavigationBar虚拟按键栏,ActionBar标题栏)、
3  * 屏幕宽高以及一些相关的特征。
4  */
public class SystemBarConfig
{

public static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";
public static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";
public static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";
public static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";
public static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";

public final int mStatusBarHeight;
public final int mActionBarHeight;
public final boolean mHasNavigationBar;
public final int mNavigationBarHeight;
public final int mNavigationBarWidth;
public final int mContentHeight;
public final int mContentWidth;
public final boolean mInPortrait;
public final float mSmallestWidthDp;

public SystemBarConfig(Activity activity)
{
Resources res = activity.getResources();
mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
mSmallestWidthDp = getSmallestWidthDp(activity);
mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME);
mActionBarHeight = getActionBarHeight(activity);
mNavigationBarHeight = getNavigationBarHeight(activity);
mNavigationBarWidth = getNavigationBarWidth(activity);
mContentHeight = getContentHeight(activity);
mContentWidth = getContentWidth(activity);
mHasNavigationBar = (mNavigationBarHeight > 0);

}

// 安卓系统允许修改系统的属性来控制navigation bar的显示和隐藏,此方法用来判断是否有修改过相关属性。
// (修改系统文件,在build.prop最后加入qemu.hw.mainkeys=1即可隐藏navigation bar)
// 相关属性模拟器中有使用。
// 当返回值等于"1"表示隐藏navigation bar,等于"0"表示显示navigation bar。
@TargetApi(19)
public String getNavBarOverride()
{
String isNavBarOverride = 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);
isNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
} catch (Throwable e)
{
isNavBarOverride = null;
}
}
return isNavBarOverride;
}

//通过此方法获取action bar的高度
@TargetApi(14)
public int getActionBarHeight(Context context)
{
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
{
TypedValue tv = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());
}
return result;
}

//通过此方法获取navigation bar的高度
@TargetApi(14)
public int getNavigationBarHeight(Context context)
{
Resources res = context.getResources();
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
{
if (hasNavBar(context))
{
String key;
if (mInPortrait)
{
key = NAV_BAR_HEIGHT_RES_NAME;
} else
{
key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME;
}
return getInternalDimensionSize(res, key);
}
}
return result;
}

//通过此方法获取navigation bar的宽度
@TargetApi(14)
public int getNavigationBarWidth(Context context)
{
Resources res = context.getResources();
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
{
if (hasNavBar(context))
{
return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);
}
}
return result;
}

//通过此方法判断是否存在navigation bar
@TargetApi(14)
public boolean hasNavBar(Context context)
{
Resources res = context.getResources();
int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android");
if (resourceId != 0)
{
boolean hasNav = res.getBoolean(resourceId);
// 查看是否有通过系统属性来控制navigation bar。
if ("1".equals(getNavBarOverride()))
{
hasNav = false;
} else if ("0".equals(getNavBarOverride()))
{
hasNav = true;
}
return hasNav;
} else
{
//可通过此方法来查看设备是否存在物理按键(menu,back,home键)。
return !ViewConfiguration.get(context).hasPermanentMenuKey();
}
}

//通过此方法获取资源对应的像素值
public int getInternalDimensionSize(Resources res, String key)
{
int result = 0;
int resourceId = res.getIdentifier(key, "dimen", "android");
if (resourceId > 0)
{
result = res.getDimensionPixelSize(resourceId);
}
return result;
}

//通过此方法获取最小一边的dp值,再通过这个dp值大小来判断设备的navigation bar是显示在底部还是右侧
@TargetApi(17)
public float getSmallestWidthDp(Activity activity)
{
DisplayMetrics metrics = new DisplayMetrics();
float widthDp;
float heightDp;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
{
//API 之后使用,获取的像素宽高包含虚拟键所占空间,在API 之前通过反射获取,
//获取的屏幕高度包含status bar和navigation bar
activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
widthDp = metrics.widthPixels / metrics.density;
heightDp = metrics.heightPixels / metrics.density;
} else
{
//获取的屏幕高度包含status bar,但不包含navigation bar
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
widthDp = metrics.widthPixels / metrics.density;
heightDp = (metrics.heightPixels + getNavigationBarWidth(activity)) / metrics.density;
}
return Math.min(widthDp, heightDp);
}

//通过此方法获取屏幕高度(不含status bar 和 navigation bar的高度)
public int getContentHeight(Activity activity)
{
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
return metrics.heightPixels - getStatusBarHeight();
}

//通过此方法获取屏幕的宽度(不含navigation bar的宽度)
public int getContentWidth(Activity activity)
{
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
return metrics.widthPixels;
}

/**
* 判断navigation bar 是显示在底部还是显示在右侧
*
* @return true表示在底部,false表示在右侧
*/
public boolean isNavigationAtBottom()
{
return (mSmallestWidthDp >=600 || mInPortrait);
}

/**
* 获取status bar状态栏高度
*
* @return 状态栏高度的像素值
*/
public int getStatusBarHeight()
{
return mStatusBarHeight;
}

/**
* 获取action bar的高度
*
* @return action bar高度的像素值
*/
public int getActionBarHeight()
{
return mActionBarHeight;
}

/**
* 判断此设备是否有navigation bar虚拟按键栏
*
* @return true表示有,false表示无
*/
public boolean hasNavigtionBar()
{
return mHasNavigationBar;
}

/**
* 获取navigation bar虚拟按键栏的高度
*
* @return 返回navigation bar虚拟按键栏的高度的像素值,如果设备没有navigation bar虚拟按键栏则返回0
*/
public int getNavigationBarHeight()
{
return mNavigationBarHeight;
}

/**
* 获取navigation bar虚拟按键栏的宽度(当navigation bar虚拟按键栏垂直显示在右侧时使用)
*
* @return 返回navigation bar虚拟按键栏的宽度的像素值,如果设备没有navigation bar虚拟按键栏则返回0
*/
public int getNavigationBarWidth()
{
return mNavigationBarWidth;
}

/**
* 获取屏幕高度(不含status bar 和 navigation bar的高度)
*
* @return 返回屏幕高度的像素值(不含status bar 和 navigation bar的高度)
*/
public int getContentHeight()
{
return mContentHeight;
}

/**
* 获取屏幕宽度(不含navigation bar的宽度)
*
* @return 返回屏幕宽度的像素值(不含navigation bar的宽度)
*/
public int getContentWidth()
{
return mContentWidth;
}

}



二、控制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 };
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: