分别用ToolBar和自定义导航栏实现沉浸式状态栏
作者:熊,我- 发布时间:2023-03-17 21:08:14
一、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给移除掉,所以无法直接调用或查看这个包中的类。如果要使用的话,可以借助这个开源项目https://github.com/anggrayudi/android-hidden-api。
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):
来源:http://www.cnblogs.com/xiongwo/p/6188329.html


猜你喜欢
- 概述本文的目的是实现以下的流程:Android/iOS native app 操作摄像头 -> 获取视频流数据 -> 人脸检测或
- 一、概述EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent,Handler,BroadCast在F
- 问题在项目过程中使用MyBatis-Puls的saveBatch一次性添加大量数据时很慢原因MyBatis-Puls的saveBatch默认
- SmartArt其实就是一个文字的可视化工具,用户可在PowerPoint,Word,Excel中使用该特性创建各种图形图表。SmartAr
- 继承JpaRepository,找不到findOne()方法问题:以前一直使用findOne(ID id);,这次用SpringBoot构建
- JMF这个多媒体开发框架太牛了,简单的几句代码就能实现一个视频播放器的开发,厉害,就是支持的格式少了一些,没关系,这个视频播放器可以播放mp
- 微服务之间token传递问题假设现在有A服务,B服务,外部使用RESTApi请求调用A服务,在请求头上有token字段,A服务使用完后,B服
- java生成json时产生栈溢出错误环境java + hibernate +html本来,java中使用json事件很正常的事,但小心有的地
- 一、准备工作1、你需要android手机应用开发基础2、科大讯飞语音识别SDK android版3、科大讯飞语音识别开发API文档4、and
- 本文实例讲述了Android开发之使用SQLite存储数据的方法。分享给大家供大家参考,具体如下:前面已经说到了几种文件的操作如shared
- 概述在Compose中,图片组件主要有两种,分别是显示图标的Icon组件和显示图片的Image组件,当我们显示一系列的小图标的时候,我们可以
- 即只能在组件布局代码后,或者在组件的前面添加注释。#注释格式:Android的XML文件注释一般采用 <!--注释内容 -->的
- 一、电量统计模块概述耗电信息在设置 -> 电量中能够非常直观的看到。注意,Android 所有功耗统计都是通过代码估算,没有集成电路参
- 前言 之前unity5.x在代码中写了debug.log..等等,打
- 本文实例为大家分享了java实现拼图游戏的具体代码,供大家参考,具体内容如下游戏说明:设计一款拼图游戏,要求点击图片按钮,实现图片按钮的移动
- Java类成员变量的默认值基本数据类型作为类的成员变量时可以不赋予初值,在方法中输出也不会报错。下面我们看看我们的八种数据类型的默认值是什么
- 微服务开发中经常有这样的需求,公司自定义了通用的请求头,需要在微服务的调用链中转发,比如在请求头中加入了token,或者某个自定义的信息un
- java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof通过返回一个布尔值来指出,这个对
- 重载:方法名相同,但参数不同的多个同名函数注意:1.参数不同的意思是参数类型、参数个数、参数顺序至少有一个不同2.返回值和异常以及访问修饰符
- SpringCloud feign无法注入接口接口:package cn.mn.app.service;import org.springf