其实我不会做这个我是在网上看了别人做的比较好的东东,然后看了翻译过来的,原文地址:http://blog.csdn.net/jdsjlzx/article/details/41643587写这个代码的人真牛逼,代码超级规范,反正比我写的好。以下为翻译内容:
/**
*当使用使用KitKat半透明的系统UI模式时,该类主要是用来管理状态栏和导航栏的色调效果
*/
public class SystemBarTintManager {
static {//静态代码块,jvm加载类时会执行这些静态的代码块,利用静态代码块可以对一些static变量进行赋值
/** 安卓允许一些系统的属性来修改导航栏的属性
* 友情链接https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Class c = Class.forName("android.os.SystemProperties");//要求JVM查找并加载指定的类android.os.SystemProperties并初始化
Method m = c.getDeclaredMethod("get", String.class);//得到被反射类中所有get方法并且方法参数为string类型的,得到的Method对象描述的不只是public方法,还包括protected、private方法,也是说只要是在类中声明的方法
// 参数为true,只要是在类中声明的目标属性均可访问,
//为false,则被反射类和反射类在同一个包中时,private目标属性不可访问,
//不在同一个包中时,private、protected目标属性均不可访问
m.setAccessible(true);//主要是为了让所有类型的属性都可以使用
//你可以在不知道具体的类的情况下,根据配置的字符串去调用一个类的方法
//qemu.hw.mainkeys代表导航栏的虚拟键得到它的值赋给sNavBarOverride变量
sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
} catch (Throwable e) {
sNavBarOverride = null;
}
}
}
/**
* 默认的系统bar的颜色值
*/
public static final int DEFAULT_TINT_COLOR = 0x99000000;
private static String sNavBarOverride;
private final SystemBarConfig mConfig;//系统工具条的配置对象
private boolean mStatusBarAvailable;//状态栏是否可利用物理条件是否满足
private boolean mNavBarAvailable; //导航栏是否可利用物理条件是否满足
private boolean mStatusBarTintEnabled;//状态栏上色可不可以
private boolean mNavBarTintEnabled;//导航栏上色可不可以
private View mStatusBarTintView;//状态栏view
private View mNavBarTintView;//导航栏view
/**
*SystemBarTintManager类构造函数,做一些初始化操作,判断状态栏与导航栏是否可利用给定其变量值
* @param activity 当前的activity
*/
@TargetApi(19)
public SystemBarTintManager(Activity activity) {
Window win = activity.getWindow();//获得当前的窗体
ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();//window中的最顶层ViewGroup的容器
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//如果当前环境sdk比19大
//检查主题的属性,在主题(theme)中设置windowTranslucentStatus为true将填充顶部的状态栏区域。(有虚拟按键的设备上)设置windowTranslucentNavigation为true将填充底部导航栏的区域。
int[] attrs = {android.R.attr.windowTranslucentStatus,
android.R.attr.windowTranslucentNavigation};
//TypedArray实例是个属性的容器,context.obtainStyledAttributes()方法返回得到
TypedArray a = activity.obtainStyledAttributes(attrs);
try {
mStatusBarAvailable = a.getBoolean(0, false);//设置状态栏是否可利用,设置默认值为false
mNavBarAvailable = a.getBoolean(1, false);//设置导航栏是否可利用,设置默认值为false
} finally {
a.recycle();//回收
}
// 获得窗体的参数属性值
WindowManager.LayoutParams winParams = win.getAttributes();
//的到透明状态的整形值与窗体的flags做与运算,如果winParams.flags与bits两个都为true那么状态栏就是可利用的,其中一个为false就不可利用了,导航栏同理
int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if ((winParams.flags & bits) != 0) {
mStatusBarAvailable = true;
}//得到导航栏的透明状态值与当前窗体的flags做与运算
bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
if ((winParams.flags & bits) != 0) {
mNavBarAvailable = true;
}
}
//根据状态栏和导航栏是否可利用和传入的当前activity初始化系统两个bar的配置信息对象
mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable);
// 设备可能没有虚拟的导航按键,所以根据刚初始化的配置信息来判断是否有,没有那么导航栏是不可利用的
if (!mConfig.hasNavigtionBar()) {
mNavBarAvailable = false;
}
//如果导航栏可利用就将窗体的最底层容器和当前的activity传入然后new一个view设置属性将其添加进最底层容器,导航栏同理
if (mStatusBarAvailable) {
setupStatusBarView(activity, decorViewGroup);
}
if (mNavBarAvailable) {
setupNavBarView(activity, decorViewGroup);
}
}
/**
* 使系统状态栏的着色view是否可见在状态栏可利用的情况下
* @param enabled true代表着色状态栏view可见(在状态栏可利用的情况下)
*/
public void setStatusBarTintEnabled(boolean enabled) {
mStatusBarTintEnabled = enabled;//状态栏色调是否可利用根据传入的参数确定
if (mStatusBarAvailable) {//状态栏可利用的话才有后续操作,如果可利用就设置状态栏色调view(指已经设置相关属性的状态栏view,查看setupStatusBarView(activity, decorViewGroup);)是否可见根据传入的参数
mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
}
}
/**
* 使系统导航栏的着色view是否可见在状态栏可利用的情况下
* @param enabled true代表着色导航栏view可见(在导航栏可利用的情况下)
*/
public void setNavigationBarTintEnabled(boolean enabled) {
mNavBarTintEnabled = enabled;//导航栏色调是否可利用根据传入的参数确定
if (mNavBarAvailable) {//导航栏可利用的话才有后续操作,如果可利用就设置导航栏色调view(指已经设置相关属性的状态栏view,查看setupNavBarView(activity, decorViewGroup)是否可见根据传入的参数
mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
}
}
/**
* 设置状态栏和导航栏的色调
* @param color 要设置的色值
*/
public void setTintColor(int color) {
setStatusBarTintColor(color);
setNavigationBarTintColor(color);
}
/**
* 设置状态栏和导航栏的资源(比如图片)
* @param res 要设置的资源
*/
public void setTintResource(int res) {
setStatusBarTintResource(res);
setNavigationBarTintResource(res);
}
/**
* 设置状态栏和导航栏的背景图片,图片以drawable形式传入
* @param drawable 要设置的drawable对象
*/
public void setTintDrawable(Drawable drawable) {
setStatusBarTintDrawable(drawable);
setNavigationBarTintDrawable(drawable);
}
/**
* 设置状态栏和导航栏的透明程度
* @param alpha 透明值
*/
public void setTintAlpha(float alpha) {
setStatusBarAlpha(alpha);
setNavigationBarAlpha(alpha);
}
/**
*设置状态栏的背景颜色
* @param color 色值
*/
public void setStatusBarTintColor(int color) {
if (mStatusBarAvailable) {
mStatusBarTintView.setBackgroundColor(color);
}
}
/**
*设置状态栏的背景资源(R.color.statusbar_bg)
* @param res 资源
*/
public void setStatusBarTintResource(int res) {
if (mStatusBarAvailable) {
mStatusBarTintView.setBackgroundResource(res);
}
}
/**
*设置状态栏的背景图片
* @param drawable
*/
@SuppressWarnings("deprecation")
public void setStatusBarTintDrawable(Drawable drawable) {
if (mStatusBarAvailable) {
mStatusBarTintView.setBackgroundDrawable(drawable);
}
}
/**
* 设置状态栏的透明程度
* @param alpha 透明值
*/
@TargetApi(11)
public void setStatusBarAlpha(float alpha) {
if (mStatusBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mStatusBarTintView.setAlpha(alpha);
}
}
/**
* 设置导航栏的颜色
* @param color 色值
*/
public void setNavigationBarTintColor(int color) {
if (mNavBarAvailable) {
mNavBarTintView.setBackgroundColor(color);
}
}
/**
* 设置指定的drawable或颜色资源系统的导航栏。
* @param res
*/
public void setNavigationBarTintResource(int res) {
if (mNavBarAvailable) {
mNavBarTintView.setBackgroundResource(res);
}
}
/**
* 设置指定的drawable到系统的导航栏。
* @param drawable
*/
@SuppressWarnings("deprecation")
public void setNavigationBarTintDrawable(Drawable drawable) {
if (mNavBarAvailable) {
mNavBarTintView.setBackgroundDrawable(drawable);
}
}
/**
* 设置导航栏的透明度
* @param alpha
*/
@TargetApi(11)
public void setNavigationBarAlpha(float alpha) {
if (mNavBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mNavBarTintView.setAlpha(alpha);
}
}
/**
*获得系统的导航栏和状态栏的配置对象
* @return 当前设备配置的系统栏配置。
*/
public SystemBarConfig getConfig() {
return mConfig;
}
/**
* 状态栏色值状态是否可利用,有用就上色
* @return True if enabled, False otherwise.
*/
public boolean isStatusBarTintEnabled() {
return mStatusBarTintEnabled;
}
/**
* 导航栏设不设置色彩啥的,一个判断标志
* @return true可利用
*/
public boolean isNavBarTintEnabled() {
return mNavBarTintEnabled;
}
private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
mStatusBarTintView = new View(context);//new一个view当做状态栏
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
params.gravity = Gravity.TOP;//设置该view的内容居中宽度最大,高度以计算的状态栏的高度为准
if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
params.rightMargin = mConfig.getNavigationBarWidth();
}
mStatusBarTintView.setLayoutParams(params);//设置属性高宽就不居中之类的
mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);//设置默认的背景颜色
mStatusBarTintView.setVisibility(View.GONE);//设置不可见
decorViewGroup.addView(mStatusBarTintView);//将其添加到当前窗体的最里面的view
}
private void setupNavBarView(Context context, ViewGroup decorViewGroup) {
mNavBarTintView = new View(context);//new一个view当做导航栏
LayoutParams params;
if (mConfig.isNavigationAtBottom()) {
params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight());//设置该view的内容居中宽度最大,高度以计算的状态栏的高度为准
params.gravity = Gravity.BOTTOM;
} else {
params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT);
params.gravity = Gravity.RIGHT;
}
mNavBarTintView.setLayoutParams(params);//设置属性高宽就不居中之类的
mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);//设置默认的背景颜色
mNavBarTintView.setVisibility(View.GONE);//设置不可见
decorViewGroup.addView(mNavBarTintView);//将其添加到当前窗体的最里面的view
}
/**
* Class which describes system bar sizing and other characteristics for the current
* device configuration.
*
*/
public static class SystemBarConfig {
private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";//状态栏的高度
private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";//导航栏的高度
private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";//横屏导航栏的高度
private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";//导航栏的宽度
private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";
private final boolean mTranslucentStatusBar;//状态栏是否透明
private final boolean mTranslucentNavBar;//导航栏是否透明
private final int mStatusBarHeight;//状态栏的高度
private final int mActionBarHeight;//ActionBar的高度
private final boolean mHasNavigationBar;//是否有导航栏
private final int mNavigationBarHeight;//导航栏的高度
private final int mNavigationBarWidth;//导航栏的宽度
private final boolean mInPortrait;//是否竖屏
private final float mSmallestWidthDp;//
//初始化配置信息
private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) {
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);
mHasNavigationBar = (mNavigationBarHeight > 0);
mTranslucentStatusBar = translucentStatusBar;
mTranslucentNavBar = traslucentNavBar;
}
/**
* 获得actionbar的高度
* @param context
* @return
*/
@TargetApi(14)
private int getActionBarHeight(Context context) {
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
//动态类型数据值的容器。主要用于资源值的控制这个类有非常多的常量。
//详情见http://android.toolib.net/reference/android/util/TypedValue.html
TypedValue tv = new TypedValue();
//根据的上下文得到的当前系统的主题,根据主题解析actionbar大小的属性值
context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
//将一个复杂的数据值转换为一个整型值,将其值作为一个整型像素大小来转换。
result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());
}
return result;
}
/**
* 获得导航栏的高度见getInternalDimensionSize()
* @param context
* @return
*/
@TargetApi(14)
private 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);//根据是横竖屏的到指定的key,根据这个key获取导航栏的高度
}
}
return result;
}
/**
* 获取导航栏的宽度见getInternalDimensionSize()
* @param context
* @return
*/
@TargetApi(14)
private 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;
}
/**
* 判断是否有导航栏
* @param context
* @return
*/
@TargetApi(14)
private 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);
// check override flag (see static block)
if ("1".equals(sNavBarOverride)) {
hasNav = false;
} else if ("0".equals(sNavBarOverride)) {
hasNav = true;
}
return hasNav;
} else { // fallback
return !ViewConfiguration.get(context).hasPermanentMenuKey();
}
}
private int getInternalDimensionSize(Resources res, String key) {
int result = 0;
//根据给定的资源名称返回一个资源id
int resourceId = res.getIdentifier(key, "dimen", "android");
if (resourceId > 0) {
//根据资源id返回一个尺寸
result = res.getDimensionPixelSize(resourceId);
}
return result;
}
@SuppressLint("NewApi")
private float getSmallestWidthDp(Activity activity) {
DisplayMetrics metrics = new DisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
} else {
// TODO this is not correct, but we don't really care pre-kitkat
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
}
float widthDp = metrics.widthPixels / metrics.density;
float heightDp = metrics.heightPixels / metrics.density;
return Math.min(widthDp, heightDp);
}
/**
*导航栏是否出现在当前设备配置的屏幕底部?在某些配置中,在屏幕右侧出现导航栏。
* @return True if navigation should appear at the bottom of the screen, False otherwise.
*/
public boolean isNavigationAtBottom() {
return (mSmallestWidthDp >= 600 || mInPortrait);
}
/**
* 获得系统状态栏的高度以像素为单位
* @return
*/
public int getStatusBarHeight() {
return mStatusBarHeight;
}
/**
*获得actionbar的高度以像素为单位
* @return
*/
public int getActionBarHeight() {
return mActionBarHeight;
}
/**
* 返回是否有导航栏
* @return True为有
*/
public boolean hasNavigtionBar() {
return mHasNavigationBar;
}
/**
* 获得系统导航栏的高度
* @return 返回导航栏的宽度 (以像素为单位). 如果手机没有导航栏,将返回0
*/
public int getNavigationBarHeight() {
return mNavigationBarHeight;
}
/**
* 获得系统导航栏的宽度
* @return 返回导航栏的宽度 (以像素为单位). 如果手机没有导航栏,将返回0
*/
public int getNavigationBarWidth() {
return mNavigationBarWidth;
}
/**
*得到布局插入任何一个系统UI的顶部,师父说为嘛出现在最上面,那是因为Gravity. top属性,状态栏就是Gravity. top,布局的最上面
*
* @param actionbar是否存在,存在的话状态栏要包含它的高度,不存在的话就不需计算它的高度了
* @return 屏幕的间隙(整型数据的像素).它就是状态栏的高度加上actionbar的高度
*/
public int getPixelInsetTop(boolean withActionBar) {
return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0);
}
/**
* 得到任何一个系统UI布局的屏幕底部间隙 ,一般屏幕在底部就是导航栏的高度了,有的横屏导航栏在右边
*
* @return 屏幕的间隙(整型数据的像素).它就是导航栏的高度
*/
public int getPixelInsetBottom() {
if (mTranslucentNavBar && isNavigationAtBottom()) {
return mNavigationBarHeight;
} else {
return 0;
}
/**
*使状态栏和导航栏隐藏
*/
@TargetApi(11)
public void mStatusBarNavBarhide( Activity activity) {
Window win = activity.getWindow();
ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();
decorViewGroup.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_FULLSCREEN
|View.SYSTEM_UI_FLAG_IMMERSIVE);
} /**
* 设置导航栏和状态栏可见
* @param 当前容器
*/
@TargetApi(11)
private void showmStatusBarNavBar( Activity activity) {
Window win = activity.getWindow();
ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();
decorViewGroup.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
/** * 得到任何一个系统UI布局的屏幕底部间隙 ,一般屏幕在底部就是导航栏的高度了,有的横屏导航栏在右边,这个是得到右边间隙
*
* @return 屏幕的间隙(整型数据的像素).它就是导航栏的高度
*/
public int getPixelInsetRight() {
if (mTranslucentNavBar && !isNavigationAtBottom()) {
return mNavigationBarWidth;
} else {
return 0;
}
}
}
}
``
`
*全文思路就是计算状态栏导航栏的高度,判断是否可用,设置一个符合我们想要的view(状态栏)将其添加到当前窗体最里层的中,至于变色啥的由于是造的view,那view就自己带有设置颜色背景图片透明度的方法,作者好聪明,至于为什么addview进去后就是状态栏和导航栏,师父说那是因为Gravity. top属性就是状态栏,也是仔细想一想,Gravity. top代表在内容的最上面,导航栏是最下面或者右边。
上面类的用法一(透明的状态栏和导航栏):
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setNavigationBarTintEnabled(true);
//将调整系统窗口布局以适应你自定义的布局,调整状态栏
android:fitsSystemWindows="true"
//http://www.tuicool.com/articles/32YRJrq
android:clipToPadding="false"
上面类的用法二(配合actionbar):
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintResource(R.color.statusbar_bg;
android:fitsSystemWindows="true"
"actionbar_bg">#FF0099CC
"statusbar_bg">#FF006080
API大于19的在给状态栏上色前要先将其透明
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setTranslucentStatus(true);
}
@TargetApi(19)
private void setTranslucentStatus(boolean on) {
Window win = getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
上面类的用法三(状态栏和导航栏均变色):
SystemBarTintManager mTintManager = new SystemBarTintManager(this);
mTintManager.setStatusBarTintEnabled(true);
mTintManager.setNavigationBarTintEnabled(true);
mTintManager.setTintColor(color);
android:fitsSystemWindows="true"
以上使用的时候要将activity透明方式一:style继承parent="android:Theme.Holo.Light.NoActionBar.TranslucentDecor"样式,方法二: if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//透明状态栏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明导航栏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
*全局沉浸式是指状态栏被隐藏,普通沉浸是指状态栏透明。
普通沉浸上面已经实现,全局沉浸如下:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
tintManager.statusvisbile(mcontent);
}
}