当前位置: 移动技术网 > 移动技术>移动开发>Android > 分别用ToolBar和自定义导航栏实现沉浸式状态栏

分别用ToolBar和自定义导航栏实现沉浸式状态栏

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

一、toolbar

1、在build.gradle中添加依赖,例如:

compile 'com.android.support:appcompat-v7:23.4.0'

2、去掉应用的actionbar。可以是修改主题theme为“noactionbar”,例如:

<style name="apptheme" parent="theme.appcompat.light.noactionbar">

或者不修改主题为"noactionbar",而在主题的style下,添加:

 <item name="windownotitle">true</item>
 <item name="windowactionbar">false</item>

第二个属性代表是否用actionbar代替titlebar。

其实,刚学的时候,感觉很纳闷,怎么又多了个titlebar?后来查了很久才发现,3.0以前,状态栏下面的是标题栏(只能显示标题等少量信息),3.0以后就变成了应用栏,也就是actionbar。

另外,我测试的时候,activity是继承于appcompatactivity,主题是appcompat类型的。这种情况下,必须要像上面那样写才有效果,少写或值不同的话,要么没效果,要么报错。

最后,上面两个属性的说明可在android.r.attr这个类中查看。

3、在xml中为toolbar添加属性

 android:fitssystemwindows="true"
 android:minheight="?attr/actionbarsize"

fitssystemwindows是toolbar实现沉浸式状态栏的关键,其大概情况是,如果设为true,就会调整这个view去留一些空间给系统窗口,如果不设置或设为false,toolbar就会和状态栏重叠在一起。

而第二个属性中,它的值全写是"?android:attr/actionbarsize",其意思是引用当前主题中的actionbarsize这个属性。更多相关说明可查看官方文档中accessing resources的部分。

上面两个属性可在android.view.view这个类中查看。

4、在java中添加判断sdk版本的代码并在用户的系统是4.4及以上时设置状态栏为透明

if (build.version.sdk_int >= build.version_codes.kitkat) {
 getwindow().addflags(windowmanager.layoutparams.flag_translucent_status);
}

无论是toolbar,还是自定义导航栏,这个操作都是实现沉浸式状态栏的关键。

因为设置状态栏为透明的这个属性,要4.4以上才能使用,所以4.4以下的系统是不能够实现沉浸式状态栏的。而在4.4到5.0的系统中,状态栏是全透明的,也就是它的颜色会跟你的toolbar和自定义导航栏的颜色一样。而在5.0以上的系统中,则是半透明的,也就看起来会比较深暗。

而我在6.0的系统上测试时,发现这一步没设置和设置了的,从效果上看,区别就是没设置时状态栏颜色浅一点,而且toolbar的padding top为0,而设置了的颜色就深一点,padding top为状态栏的高度。具体有什么影响,还不清楚。但这会让自定义导航的外观变形,它会增加状态栏的高度,但又没有让这部分与状态栏重叠,就导致效果变形。

5、最后在java中添加

setsupportactionbar(mtoolbar);

toolbar的布局代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.toolbar
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:id="@+id/tool_bar"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="@color/colorprimary"
 android:elevation="4dp"
 android:fitssystemwindows="true"
 android:minheight="?android:attr/actionbarsize"
 app:title="toolbar"
 app:subtitle="toolbar"/>

 效果图(android 6.0):

二、自定义导航栏topbar

1、设置窗口为无标题,上面第2步中的两个方法都可以实现,或者是在java中添加如下代码:

requestwindowfeature(window.feature_no_title);

注意在添加这句代码时,确保是在加载布局内容之前,也就是oncreate的setcontentview之前。在《android群英传》“android控件架构”,这一节中解释了为什么requestwindowfeature()需要在setcontentview()之前。

另外,我发现如果该activity是继承appcompatactivity的话,只写上面的这句代码是没有变化的,显示的还是actionbar。但如果是继承fragmentactivity的话,就有效果,也就说上面第2步中的第二个方法,只添加其中任意一个属性都是可以的。至于是什么原因,我还没弄清楚。

2、同上面第4步,判断系统版本并按需设置状态栏为透明

3、获取状态栏的高度

protected int getstatusheight() {
 try {
 class<?> c = class.forname("com.android.internal.r$dimen"); // 获得与字符串对应的class对象
 object object = c.newinstance(); // 创建这个class的实例对象
 field field = c.getfield("status_bar_height"); // 拿到字符串对应的变量
 int x = integer.parseint(field.get(object).tostring()); // 通过这个实例对象拿到这个变量的值,再转换类型,最后转为整型,变为一个资源id
 return getresources().getdimensionpixelsize(x);
 } catch (exception e) {
 e.printstacktrace();
 }
 return 0;
}

这部分代码是利用java的反射机制来实现的,因为这个internal包默认会被sdk/platforms/android-version中的android.jar给移除掉,所以无法直接调用或查看这个包中的类。如果要使用的话,可以借助这个开源项目。

4、获取自定义topbar的高度并修改布局参数

protected void setstatusbar() {
 if (build.version.sdk_int >= build.version_codes.kitkat) {
 final viewgroup viewgroup = (viewgroup) findviewbyid(r.id.top_bar);
 final int statusheight = getstatusheight();
 viewgroup.post(new runnable() {
  @override
  public void run() {
  int topbarheight = viewgroup.getheight();
  linearlayout.layoutparams layoutparams = (linearlayout.layoutparams) viewgroup.getlayoutparams();
  layoutparams.height = statusheight + topbarheight;
  viewgroup.setlayoutparams(layoutparams);
  }
 });
 }
}

因为在include这个topbar的布局文件中,其父布局是linearlayout,而topbar的父布局是relativelayout,所以这里先要转成viewgroup,等getlayoutparams时,再转成linearlayout.layoutparams。

topbar的布局:

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/top_bar"
 android:layout_width="match_parent"
 android:layout_height="49dp"
 android:background="@color/colorprimary"
 android:gravity="bottom">
 <relativelayout
 android:layout_width="match_parent"
 android:layout_height="49dp">
 <textview
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_centerinparent="true"
  android:text="@string/app_name"
  android:textsize="24sp"
  android:textcolor="#ffffff"/>
 </relativelayout>
</relativelayout>

因为这个布局的高度会在代码中动态地修改,即49dp加上状态栏的高度,所以只有一个层级的结构的话,那导航栏的内容就会往上偏。所以要嵌套多一层来维持导航栏的高度,同时在最外层的布局中,添加android:gravity="bottom"这个属性来保证导航栏不往上偏。

效果图(android 6.0):

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持移动技术网!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网