Android 透明化系统状态栏

来源:互联网 发布:梦想的数据 编辑:程序博客网 时间:2024/06/04 22:19

1 引言

对于状态栏,在4.4版本之前Android是不可以自定义状态栏的,在4.4版本Android推出了一个透明状态栏的概念,可以使手机最顶部的状态栏的颜色全透明,并且颜色可以定义;5.0又推出了Material Design,这个时候的状态栏就变成了半透明的颜色。因此,系统状态栏颜色随app主题颜色变化而变化这一特性,也只能将这一特性应用在android4.4以上的手机,无法做到全部适配。

1 相关背景知识介绍

1.1 “沉浸式状态栏”误区

在写这篇文章的时候我查了很多资料,也了解到了针对Android状态栏很多误区,包括概念的误区和使用的误区。因此,我们先了解下相关基础知识。

System Bar

System bars,包含[1]状态栏,和[2]导航栏。

Immersive full-screen mode 沉浸模式

To provide your app with a layout that fills the entire screen, the new SYSTEM_UI_FLAG_IMMERSIVE flag for setSystemUiVisibility()(when combined with SYSTEM_UI_FLAG_HIDE_NAVIGATION enables a new immersivefull-screen mode. While immersive full-screen mode is enabled, your activity continues to receive all touch events. The user can reveal the system bars with an inward swipe along the region where the system bars normally appear. This clears the SYSTEM_UI_FLAG_HIDE_NAVIGATION flag (and the SYSTEM_UI_FLAG_FULLSCREEN flag, if applied) so the system bars remain visible. However, if you’d like the system bars to hide again after a few moments, you can instead use the SYSTEM_UI_FLAG_IMMERSIVE_STICKY flag.

通过flag设置可以隐藏status bar(状态栏)navigation bar使屏幕全屏,让Activity接收所有的(整个屏幕的)触摸事件。

Translucent Bars 透明栏

You can now make the system bars partially translucent with new themes, Theme.Holo.NoActionBar.TranslucentDecor and Theme.Holo.Light.NoActionBar.TranslucentDecor.By enabling translucent system bars, your layout will fill the area behind the system bars, so you must also enable fitsSystemWindows for the portion of your layout that should not be covered by the system bars.
If you’re creating a custom theme, set one of these themes as the parent theme or include the windowTranslucentNavigation and windowTranslucentStatus style properties in your theme.

可以通过系统新的主题来设置System bar 半透明,也就是可以使得布局侵入系统栏的后面,当然,必须启用fitsSystemWindows属性来调整布局才不至于被系统栏覆盖。

WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,Added in API level 19,如果这个flag被设置,View.SYSTEM_UI_FLAG_LAYOUT_STABLE 和 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 这两个flag会被自动添加到system UI visibility中。

三者之间的关系和区别


透明栏是设置状态栏和导航栏透明度的;
沉浸模式是隐藏显示状态栏和导航栏的;

1.2 fitsSystemWindows

官方描述:

Boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.

这个一个boolean值的内部属性,让view可以根据系统窗口(如status bar)来调整自己的布局,如果值为true,就会调整view的paingding属性来给system windows留出空间.

因此,设置fitsSystemWindows 可以确保你的内容不会和系统窗口重叠。

1.3Android 视图结构

Activity->PhoneWindow->DecoView

  1. 在Android中,Window是个抽象的概念,Android中Window的具体实现类是PhoneWindow,Activity和Dialog中的Window对象都是PhoneWindow。一个Activity对应着一个PhoneWindow对象,是一对一的关系,如果从Activity A启动到Activity B,那么Activity B会创建一个自己的PhoneWindow对象。

2.PhoneWindow管理着整个屏幕的内容,不包括屏幕最顶部的系统状态条。所以,PhoneWindow或者Window是与应用的一个页面所相关联。

3.PhoneWindow同时管理着ActionBar和下面的内容主题,setContentView()方法是用来设置内容主体的,而setTitle()等其他方法就是操作ActionBar的,Window中定义的requestFeature()等方法,有很多与ActionBar属性相关的设置。另外这些方法都是公有方法,显然是为了给客户端程序员调用的,也进一步佐证了这些操作的意义与作用。

4.PhoneWindow自己并不是一个视图(View),它的成员变量mDecor才是整个界面的视图,mDecor是在generateLayout()的时候被填充出来的,而actionBar和contentParent两个视图都是通过findViewById()直接从mDecor中获取出来的。

DecoView


如上图DecorView的子元素是个linearLayout的view(1),view(1)中包含两个frameLayout(20,21)title bar在20 而我们setContentView的内容在21里面。21这个frameLayout的id就是’content’。

从上述两幅图的介绍,我们可以了解到界面视图的包含关系和位置关系;我们还可以了解到状态栏和Activity对应的视图处于不同层,我们可以利用透明度和位置偏移来处理达到我们想要的透明状态栏效果。

2 解决方案

目前查询到有多种解决方案,核心都是使用系统透明状态栏Translucent Bars,然后将ActionBar 或者ToolBar或者其他视图的背景颜色或者背景图片延伸至状态栏,以达到类似于沉浸模式的效果。

解决方案思路:

第一步:状态栏设置成半透明

通过介绍Translucent Bars我们可以知道,将Translucent Bars设置成半透明的话,就可以将我们自己的layout布局侵入状态栏;状态栏设置成半透明;
透明设置有两种实现方式:

  • 第一种:代码中硬编码;

  • 第二种:在style文件中设置主题属性。

第二步:布局入侵状态栏错位问题解决

由于状态栏设置成半透明,我们自己的layout布局会入侵到状态栏,那么我们的actionbar 或者toolbar的内容也就可能上移到状态栏里面去,因此我们必须要解决layout上移的问题。
目前有三种实现方式:

  • 第一种:在最外层layout文件 设置 android:fitsSystemWindows=”true” 这个属性;

  • 第二种:在使用toolbar的布局中,toolbar的加上 android:paddingTop=”@dimen/toolbar_padding_top” 其中toolbar_padding_top是 status_bar_height的高度;

  • 第三种:在PhoneWindow 的DecorView 上添加一个和状态栏大小颜色相同的矩形条高度的矩形。

根据上述两种步骤,我们可以任意选择步骤一、步骤二的其中的一种实现方式进行组合实现。
但是步骤一的状态栏半透明设置参数windowTranslucentStatus 在values-v19 的sytle.xml中设置windowTranslucentStatus属性为true,在某些手机会不起效,所以还是采用代码的形式进行设置稳妥;

步骤二中的第二种方式需要计算状态栏status_bar_height的高度,考虑到国内android手机的系统深度定制,不同手机的status_bar_height高度可能不一致,因此这个设置可能会有不准确的时候;

步骤三中,添加一个和状态栏大小颜色相同的矩形条高度的矩形,这个方法针对想将背景图片入侵到状态栏的效果就不能解决了。

因此,我们建议使用状态栏半透明在代码中硬编码,布局入侵错误,使用系统提供的fitsSystemWindows属性来解决。

3 实践方案

根据上面描述的,我们给出如下解决方案。

3.1 style 主题:

使用Theme.AppCompat.Light.NoActionBar(toolbar的兼容主题):既可以适配使用toolbar(由于google已经不再建议使用action bar了,而是推荐使用toolbar,且toolbar的使用更加的灵活,所以toolbar和actionbar的选择也没什么好纠结的)和不使用toolbar的情况(即自定义topBar布局)。



@color/colorPrimary
@color/colorPrimaryDark
@color/colorAccent

3.2 布局

基类布局 activity_base.xml

工具栏布局toolbar_layout.xml

测试界面布局 activity_test_status.xml

3.3 java代码

基类代码BaseActivity.java

public class BaseActivity extends AppCompatActivity {

private LinearLayout rootLayout;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    // 这句很关键,注意是调用父类的方法    super.setContentView(R.layout.activity_base);    // 经测试在代码里直接声明透明状态栏更有效    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {        Window window =  getWindow();        // Translucent status bar        window.setFlags(                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);    }    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {        Window window = getWindow();        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS                | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);        window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);        window.setStatusBarColor(Color.TRANSPARENT);        window.setNavigationBarColor(Color.TRANSPARENT);    }    initToolbar();}private void initToolbar() {    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);    if (toolbar != null) {        setSupportActionBar(toolbar);    }}@Overridepublic void setContentView(int layoutId) {    setContentView(View.inflate(this, layoutId, null));}@Overridepublic void setContentView(View view) {    rootLayout = (LinearLayout) findViewById(R.id.root_layout);    if (rootLayout == null) return;    rootLayout.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));    initToolbar();}

}

BaseActivity关键代码解释:
设置透明栏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
localLayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
}

void setContentView(int layoutId)

所有子类实现setContentView设置布局,在包括Toolbar的基类布局上addView添加子类布局。

测试界面代码 TestStatusActivity.java

public class TestStatusActivity extends BaseActivity {

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_test_status);}

}

4参考链接

http://hukai.me/android-training-course-in-chinese/ui/system-ui/index.html
http://hukai.me/android-training-course-in-chinese/ui/system-ui/immersive.html
http://www.zhihu.com/question/27040217
http://images2015.cnblogs.com/blog/79442/201606/79442-20160617151415698-1016742976.png
http://gold.xitu.io/entry/56c3d26679bc44005128cabc
http://blog.csdn.net/lmj623565791/article/details/48649563
http://www.cnblogs.com/beenupper/archive/2012/07/13/2589749.HTML
http://www.jianshu.com/p/c223b993b1ec
http://www.tuicool.com/articles/uqaQru7
http://www.cnblogs.com/bastard/archive/2012/04/10/2440577.html
http://www.360doc.com/content/13/0606/01/9171956_290805095.shtml
http://www.cnblogs.com/bastard/archive/2012/04/10/2440577.html
http://blog.csdn.net/mybeta/article/details/50760323
http://www.jianshu.com/p/aca4fd6743b1
http://stormzhang.com/android/2015/08/16/boohee-toolbar/
http://www.jianshu.com/p/aca4fd6743b1
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1122/3712.html

0 0
原创粉丝点击