当前位置: 移动技术网 > IT编程>移动开发>Android > Android自定义状态栏颜色与APP风格保持一致的实现方法

Android自定义状态栏颜色与APP风格保持一致的实现方法

2019年07月24日  | 移动技术网IT编程  | 我要评论

均安乐园网,风云足球节目表,妖精的尾巴漫画下载

我们知道ios上的应用,状态栏的颜色总能与应用标题栏颜色保持一致,用户体验很不错,那安卓是否可以呢?若是在安卓4.4之前,答案是否定的,但在4.4之后,谷歌允许开发者自定义状态栏背景颜色啦,这是个不错的体验!若你手机上安装有最新版的qq,并且你的安卓sdk版本是4.4及以上,你可以看下它的效果:

实现此功能有两种方法:

1.在xml中设置主题或自定义style;

theme.holo.light.noactionbar.translucentdecor
theme.holo.noactionbar.translucentdecor
<style name="apptheme" parent="appbasetheme"> 
<!-- status bar --> 
<item name="android:windowtranslucentstatus">true</item> 
<!-- navigation bar --> 
<item name="android:windowtranslucentnavigation">true</item> 
</style>

鉴于市面上各种手机的sdk的各种版本,不建议采用这种方法;

2.在代码中控制;

可以首先创建一个baseactivity,在oncreate方法中进行处理:

@override 
protected void oncreate(bundle savedinstancestate) { 
super.oncreate(savedinstancestate); 
if (build.version.sdk_int >= build.version_codes.kitkat) { 
settranslucentstatus(true); 
systembartintmanager tintmanager = new systembartintmanager(this); 
tintmanager.setstatusbartintenabled(true); 
tintmanager.setstatusbartintresource(r.color.top_bg_color);//通知栏所需颜色 
} 
setcontentview(r.layout.main_activity); 
} 
@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); 
}

需注意的是, tintmanager.setstatusbartintresource(r.color.top_bg_color);这一步的颜色值(即把你的状态栏颜色与你的标题栏颜色保持一致)要写在color.xml中去,如果用color.prasecolor则会报错。

systembartintmanager.java源码:

import android.annotation.suppresslint; 
import android.annotation.targetapi; 
import android.app.activity; 
import android.content.context; 
import android.content.res.configuration; 
import android.content.res.resources; 
import android.content.res.typedarray; 
import android.graphics.drawable.drawable; 
import android.os.build; 
import android.util.displaymetrics; 
import android.util.typedvalue; 
import android.view.gravity; 
import android.view.view; 
import android.view.viewconfiguration; 
import android.view.viewgroup; 
import android.view.window; 
import android.view.windowmanager; 
import android.widget.framelayout.layoutparams; 
import java.lang.reflect.method; 
/** 
* class to manage status and navigation bar tint effects when using kitkat 
* translucent system ui modes. 
* 
*/ 
@suppresswarnings({ "rawtypes", "unchecked" }) 
public class systembartintmanager { 
static { 
// android allows a system property to override the presence of the navigation bar. 
// used by the emulator. 
// see 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"); 
method m = c.getdeclaredmethod("get", string.class); 
m.setaccessible(true); 
snavbaroverride = (string) m.invoke(null, "qemu.hw.mainkeys"); 
} catch (throwable e) { 
snavbaroverride = null; 
} 
} 
} 
/** 
* the default system bar tint color value. 
*/ 
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; 
private view mnavbartintview; 
/** 
* constructor. call this in the host activity oncreate method after its 
* content view has been set. you should always create new instances when 
* the host activity is recreated. 
* 
* @param activity the host activity. 
*/ 
@targetapi(19) 
public systembartintmanager(activity activity) { 
window win = activity.getwindow(); 
viewgroup decorviewgroup = (viewgroup) win.getdecorview(); 
if (build.version.sdk_int >= build.version_codes.kitkat) { 
// check theme attrs 
int[] attrs = {android.r.attr.windowtranslucentstatus, 
android.r.attr.windowtranslucentnavigation}; 
typedarray a = activity.obtainstyledattributes(attrs); 
try { 
mstatusbaravailable = a.getboolean(0, false); 
mnavbaravailable = a.getboolean(1, false); 
} finally { 
a.recycle(); 
} 
// check window flags 
windowmanager.layoutparams winparams = win.getattributes(); 
int bits = windowmanager.layoutparams.flag_translucent_status; 
if ((winparams.flags & bits) != 0) { 
mstatusbaravailable = true; 
} 
bits = windowmanager.layoutparams.flag_translucent_navigation; 
if ((winparams.flags & bits) != 0) { 
mnavbaravailable = true; 
} 
} 
mconfig = new systembarconfig(activity, mstatusbaravailable, mnavbaravailable); 
// device might not have virtual navigation keys 
if (!mconfig.hasnavigtionbar()) { 
mnavbaravailable = false; 
} 
if (mstatusbaravailable) { 
setupstatusbarview(activity, decorviewgroup); 
} 
if (mnavbaravailable) { 
setupnavbarview(activity, decorviewgroup); 
} 
} 
/** 
* enable tinting of the system status bar. 
* 
* if the platform is running jelly bean or earlier, or translucent system 
* ui modes have not been enabled in either the theme or via window flags, 
* then this method does nothing. 
* 
* @param enabled true to enable tinting, false to disable it (default). 
*/ 
public void setstatusbartintenabled(boolean enabled) { 
mstatusbartintenabled = enabled; 
if (mstatusbaravailable) { 
mstatusbartintview.setvisibility(enabled ? view.visible : view.gone); 
} 
} 
/** 
* enable tinting of the system navigation bar. 
* 
* if the platform does not have soft navigation keys, is running jelly bean 
* or earlier, or translucent system ui modes have not been enabled in either 
* the theme or via window flags, then this method does nothing. 
* 
* @param enabled true to enable tinting, false to disable it (default). 
*/ 
public void setnavigationbartintenabled(boolean enabled) { 
mnavbartintenabled = enabled; 
if (mnavbaravailable) { 
mnavbartintview.setvisibility(enabled ? view.visible : view.gone); 
} 
} 
/** 
* apply the specified color tint to all system ui bars. 
* 
* @param color the color of the background tint. 
*/ 
public void settintcolor(int color) { 
setstatusbartintcolor(color); 
setnavigationbartintcolor(color); 
} 
/** 
* apply the specified drawable or color resource to all system ui bars. 
* 
* @param res the identifier of the resource. 
*/ 
public void settintresource(int res) { 
setstatusbartintresource(res); 
setnavigationbartintresource(res); 
} 
/** 
* apply the specified drawable to all system ui bars. 
* 
* @param drawable the drawable to use as the background, or null to remove it. 
*/ 
public void settintdrawable(drawable drawable) { 
setstatusbartintdrawable(drawable); 
setnavigationbartintdrawable(drawable); 
} 
/** 
* apply the specified alpha to all system ui bars. 
* 
* @param alpha the alpha to use 
*/ 
public void settintalpha(float alpha) { 
setstatusbaralpha(alpha); 
setnavigationbaralpha(alpha); 
} 
/** 
* apply the specified color tint to the system status bar. 
* 
* @param color the color of the background tint. 
*/ 
public void setstatusbartintcolor(int color) { 
if (mstatusbaravailable) { 
mstatusbartintview.setbackgroundcolor(color); 
} 
} 
/** 
* apply the specified drawable or color resource to the system status bar. 
* 
* @param res the identifier of the resource. 
*/ 
public void setstatusbartintresource(int res) { 
if (mstatusbaravailable) { 
mstatusbartintview.setbackgroundresource(res); 
} 
} 
/** 
* apply the specified drawable to the system status bar. 
* 
* @param drawable the drawable to use as the background, or null to remove it. 
*/ 
@suppresswarnings("deprecation") 
public void setstatusbartintdrawable(drawable drawable) { 
if (mstatusbaravailable) { 
mstatusbartintview.setbackgrounddrawable(drawable); 
} 
} 
/** 
* apply the specified alpha to the system status bar. 
* 
* @param alpha the alpha to use 
*/ 
@targetapi(11) 
public void setstatusbaralpha(float alpha) { 
if (mstatusbaravailable && build.version.sdk_int >= build.version_codes.honeycomb) { 
mstatusbartintview.setalpha(alpha); 
} 
} 
/** 
* apply the specified color tint to the system navigation bar. 
* 
* @param color the color of the background tint. 
*/ 
public void setnavigationbartintcolor(int color) { 
if (mnavbaravailable) { 
mnavbartintview.setbackgroundcolor(color); 
} 
} 
/** 
* apply the specified drawable or color resource to the system navigation bar. 
* 
* @param res the identifier of the resource. 
*/ 
public void setnavigationbartintresource(int res) { 
if (mnavbaravailable) { 
mnavbartintview.setbackgroundresource(res); 
} 
} 
/** 
* apply the specified drawable to the system navigation bar. 
* 
* @param drawable the drawable to use as the background, or null to remove it. 
*/ 
@suppresswarnings("deprecation") 
public void setnavigationbartintdrawable(drawable drawable) { 
if (mnavbaravailable) { 
mnavbartintview.setbackgrounddrawable(drawable); 
} 
} 
/** 
* apply the specified alpha to the system navigation bar. 
* 
* @param alpha the alpha to use 
*/ 
@targetapi(11) 
public void setnavigationbaralpha(float alpha) { 
if (mnavbaravailable && build.version.sdk_int >= build.version_codes.honeycomb) { 
mnavbartintview.setalpha(alpha); 
} 
} 
/** 
* get the system bar configuration. 
* 
* @return the system bar configuration for the current device configuration. 
*/ 
public systembarconfig getconfig() { 
return mconfig; 
} 
/** 
* is tinting enabled for the system status bar? 
* 
* @return true if enabled, false otherwise. 
*/ 
public boolean isstatusbartintenabled() { 
return mstatusbartintenabled; 
} 
/** 
* is tinting enabled for the system navigation bar? 
* 
* @return true if enabled, false otherwise. 
*/ 
public boolean isnavbartintenabled() { 
return mnavbartintenabled; 
} 
private void setupstatusbarview(context context, viewgroup decorviewgroup) { 
mstatusbartintview = new view(context); 
layoutparams params = new layoutparams(layoutparams.match_parent, mconfig.getstatusbarheight()); 
params.gravity = gravity.top; 
if (mnavbaravailable && !mconfig.isnavigationatbottom()) { 
params.rightmargin = mconfig.getnavigationbarwidth(); 
} 
mstatusbartintview.setlayoutparams(params); 
mstatusbartintview.setbackgroundcolor(default_tint_color); 
mstatusbartintview.setvisibility(view.gone); 
decorviewgroup.addview(mstatusbartintview); 
} 
private void setupnavbarview(context context, viewgroup decorviewgroup) { 
mnavbartintview = new view(context); 
layoutparams params; 
if (mconfig.isnavigationatbottom()) { 
params = new layoutparams(layoutparams.match_parent, mconfig.getnavigationbarheight()); 
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); 
} 
/** 
* 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; 
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; 
} 
@targetapi(14) 
private 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; 
} 
@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); 
} 
} 
return result; 
} 
@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; 
} 
@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; 
int resourceid = res.getidentifier(key, "dimen", "android"); 
if (resourceid > 0) { 
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); 
} 
/** 
* should a navigation bar appear at the bottom of the screen in the current 
* device configuration? a navigation bar may appear on the right side of 
* the screen in certain configurations. 
* 
* @return true if navigation should appear at the bottom of the screen, false otherwise. 
*/ 
public boolean isnavigationatbottom() { 
return (msmallestwidthdp >= 600 || minportrait); 
} 
/** 
* get the height of the system status bar. 
* 
* @return the height of the status bar (in pixels). 
*/ 
public int getstatusbarheight() { 
return mstatusbarheight; 
} 
/** 
* get the height of the action bar. 
* 
* @return the height of the action bar (in pixels). 
*/ 
public int getactionbarheight() { 
return mactionbarheight; 
} 
/** 
* does this device have a system navigation bar? 
* 
* @return true if this device uses soft key navigation, false otherwise. 
*/ 
public boolean hasnavigtionbar() { 
return mhasnavigationbar; 
} 
/** 
* get the height of the system navigation bar. 
* 
* @return the height of the navigation bar (in pixels). if the device does not have 
* soft navigation keys, this will always return 0. 
*/ 
public int getnavigationbarheight() { 
return mnavigationbarheight; 
} 
/** 
* get the width of the system navigation bar when it is placed vertically on the screen. 
* 
* @return the width of the navigation bar (in pixels). if the device does not have 
* soft navigation keys, this will always return 0. 
*/ 
public int getnavigationbarwidth() { 
return mnavigationbarwidth; 
} 
/** 
* get the layout inset for any system ui that appears at the top of the screen. 
* 
* @param withactionbar true to include the height of the action bar, false otherwise. 
* @return the layout inset (in pixels). 
*/ 
public int getpixelinsettop(boolean withactionbar) { 
return (mtranslucentstatusbar ? mstatusbarheight : 0) + (withactionbar ? mactionbarheight : 0); 
} 
/** 
* get the layout inset for any system ui that appears at the bottom of the screen. 
* 
* @return the layout inset (in pixels). 
*/ 
public int getpixelinsetbottom() { 
if (mtranslucentnavbar && isnavigationatbottom()) { 
return mnavigationbarheight; 
} else { 
return 0; 
} 
} 
/** 
* get the layout inset for any system ui that appears at the right of the screen. 
* 
* @return the layout inset (in pixels). 
*/ 
public int getpixelinsetright() { 
if (mtranslucentnavbar && !isnavigationatbottom()) { 
return mnavigationbarwidth; 
} else { 
return 0; 
} 
} 
} 
}

引用自:https://github.com/jgilfelt/systembartint

代码复制进你的项目即可,好了,这些工作完成之后我们来看下效果:

貌似已经达到效果了,但仔细观察,好像标题栏被提上去了,就是说app界面全屏了,状态了盖在了app上,恩,这并非我们想要的效果,那如何将界面从状态栏下部开始呢,只需要在activity的布局文件最外层控件加上一个属性:

android:fitssystemwindows="true"就可以啦!看下效果:

ok,大功告成!

ps:在使用过程中发现了一些问题,使用以上方法对单个activity有效,但是对继承了tabactivity的导航页怎么办呢?假如mainactivity继承了tabactivity,tab1activity、tab2activity、tab3activity是三个子项,那么设置状态栏的代码需写在mainactivity中,而 android:fitssystemwindows="true"需写在三个子activity的xml布局文件中,这样设置后仍然有问题,就是进入应用后首页也就是tab1activity没有问题,而tab2activity、tab3activity却没达到效果,它们的效果相当于未加android:fitssystemwindows="true"时的效果,期初我怀疑是activity不同的原因,因此我把tab1activity和tab3activity调了下位置,结果tab3activity成为首页后正常,而tab1activity又不正常了,百思不得姐,最后实在没办法,就在tab2activity、tab3activity的oncreate方法中加了几句代码:

if (build.version.sdk_int >= build.version_codes.kitkat) { 
((linearlayout)findviewbyid(r.id.ll)).setpadding(0, sysutils.getstatusheight(this), 0,0); 
}

意思是,先求出状态栏高度,然后设置最外层控件的paddingtop值为状态栏高度,结果正好达到效果,至于为什么只有首页activity可以达到效果,而后面的子项无法达到效果,本人也在郁闷中,有知道的朋友可以分享下!

状态栏高度算法:

/** 
* 状态栏高度算法 
* @param activity 
* @return 
*/ 
public static int getstatusheight(activity activity){ 
int statusheight = 0; 
rect localrect = new rect(); 
activity.getwindow().getdecorview().getwindowvisibledisplayframe(localrect); 
statusheight = localrect.top; 
if (0 == statusheight){ 
class<?> localclass; 
try { 
localclass = class.forname("com.android.internal.r$dimen"); 
object localobject = localclass.newinstance(); 
int i5 = integer.parseint(localclass.getfield("status_bar_height").get(localobject).tostring()); 
statusheight = activity.getresources().getdimensionpixelsize(i5); 
} catch (classnotfoundexception e) { 
e.printstacktrace(); 
} catch (illegalaccessexception e) { 
e.printstacktrace(); 
} catch (instantiationexception e) { 
e.printstacktrace(); 
} catch (numberformatexception e) { 
e.printstacktrace(); 
} catch (illegalargumentexception e) { 
e.printstacktrace(); 
} catch (securityexception e) { 
e.printstacktrace(); 
} catch (nosuchfieldexception e) { 
e.printstacktrace(); 
} 
} 
return statusheight; 
}

以上所述是小编给大家介绍的android自定义状态栏颜色与app风格保持一致的实现方法,希望对大家有所帮助

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网