最近对“爸比讲故事”Android版本进行代码重构的时候,对之前版本的大部分界面的头部侵入式效果,作了一个总结和梳理,在期间查阅了thinkcool的博客和结合亲身实践,总结了2种侵入式实现的不同思路:
两种方式都会使用到Android的一个属性:fitsSystemWindows
第一种:不添加view覆盖status bar的方式,在Toolbar控件上添加fitSystemWindows属性为true
首先来看看这种方式在不同版本手机的表现方式
1、Android SDK 4.3(level 18)以下的表现效果为:APP 的内容不被上拉到状态,不占据status bar,不透明效果
2、Android SDK 5.1 (level 22)华为畅享5s的表现效果为:占据status bar,全透明效果
3、Android SDK 5.1 (level 22)vivio手机的表现效果为:status bar半透明效果
fitSystemWindows属性:
官方描述:
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留出空间....
实际效果:
当status bar为透明或半透明时(4.4以上),系统会设置view的paddingTop值为一个适合的值(status bar的高度)让view的内容不被上拉到状态栏,当在不占据status bar的情况下(4.4以下)会设置paddingTop值为0(因为没有占据status bar所以不用留出空间)。
主题:
使用Theme.AppCompat.Light.NoActionBar(toolbar的兼容主题):既可以适配使用toolbar(由于google已经不再建议使用action bar了,而是推荐使用toolbar,且toolbar的使用更加的灵活,所以toolbar和actionbar的选择也没什么好纠结的)和不使用toolbar的情况(即自定义topBar布局)。
// Toobar的style
<style name="Toolbar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:minHeight">?attr/actionBarSize</item>
<item name="android:background">?attr/colorPrimary</item>
<item name="android:fitsSystemWindows">true</item>
<item name="android:theme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
<item name="popupTheme">@style/ThemeOverlay.AppCompat.Light</item>
</style>
1)AndroidManifest.xml中:使用Theme.AppCompat.Light.NoActionBar主题
<application
android:name=".app.BBApp"
android:allowBackup="true"
android:icon="@mipmap/icon_72_2x"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" // 引入了@style/AppTheme
tools:replace="android:allowBackup">
<!--引导页-->
<activity
android:name=".activity.ActivityWelcome"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Transparent.Splash.Fullscreen"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 主界面 -->
<activity
android:name=".activity.ActivityHome"
android:label="@string/app_name"
android:theme="@style/AppTheme" // 引入了@style/AppTheme
android:screenOrientation="portrait">
</activity>
</application>
// @style/AppTheme对应的样式为:
<!-- 这里面的内容根据你自己项目做修改 -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!--colorPrimaryDark对应状态栏的颜色-->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<!--colorPrimary对应ActionBar的颜色-->
<item name="colorPrimary">@color/colorPrimary</item>
<!-- 底部导航栏的颜色 -->
<item name="android:navigationBarColor" tools:targetApi="lollipop">
@color/navigationBarColor
</item>
<item name="android:windowBackground">@color/windowBackground</item>
<!--colorAccent 对应EditText编辑时、RadioButton选中、CheckBox等选中时的颜色-->
<item name="colorAccent">@color/colorAccent</item>
</style>
2)activity的layout.xml为:
// layout/activity_home.xml
// 文件中:
// 1、引入了inc_toolbar.xml布局
// 2、不需要在外部容器id为ll_home的LinearLayout中添加fitsSystemWindows属性
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll_home"
style="@style/MatchMatch.Vertical"
android:background="@android:color/white"
android:orientation="vertical">
<include layout="@layout/inc_toolbar"/>
<Button
style="@style/DemoBtn"
android:onClick="testSwipeBack"
android:text="测试滑动返回"/>
<Button
style="@style/DemoBtn"
android:onClick="testSwipeDelete"
android:text="测试滑动删除"/>
</LinearLayout>
// layout/inc_toolbar.xml
// 引入了android.support.v7.widget.Toolbar这个控件
// 引用了@style/Toolbar
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
style="@style/Toolbar"/>
// @style/Toolbar的样式
// 1、android:layout_height建议设置为wrap_content
// 2、android:minHeight设置为?attr/actionBarSize
// 3、android:fitsSystemWindows设置为true
<style name="Toolbar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:minHeight">?attr/actionBarSize</item>
<item name="android:background">?attr/colorPrimary</item>
<item name="android:fitsSystemWindows">true</item>
<item name="android:theme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
<item name="popupTheme">@style/ThemeOverlay.AppCompat.Light</item>
</style>
3)在activity_home对应的ActivityHome.java文件中:
// 必须要找到这个Toolbar组件,然后调用setSupportActionBar方法,否则会出现Toolbar各种显示不正确的问题
/**
* 「必须在 Application 的 onCreate 方法中执行
* BGASwipeBackManager.getInstance().init(this) 来初始化滑动返回」
*/
public class ActivityHome extends BaseActivity {
@BindView(R.id.toolbar)
Toolbar mToolbar;
// 首页不需要支持滑动返回,重写该方法永久禁用当前界面的滑动返回功能
@Override
public boolean isSupportSwipeBack() {
return false;
}
@Override
protected int getLayoutId() {
return R.layout.activity_home;
}
@Override
protected void initView() {
setSupportActionBar(mToolbar);
}
@Override
public void onBackPressed() {
finish();
}
}
4)在BaseActivity.java中
我们通过判断当前sdk_int大于4.4(kitkat),则通过代码的形式设置status bar为透明(这里其实可以通过values-v19 的sytle.xml里设置windowTranslucentStatus属性为true来进行设置,但是在某些手机会不起效,所以采用代码的形式进行设置)。还需要注意的是我们这里的AppCompatAcitivity是android.support.v7.app.AppCompatActivity支持包中的AppCompatAcitivity,也是为了在低版本的android系统中兼容toolbar。
// 下面设置status bar透明的代码段中Build.VERSION_CODES.KITKAT = 19,
// 也就是SDK 为4.4的版本,大于4.4以上的状态栏设置为透明状态;
// 这也就是为什么本文开头演示的【效果1】status bar为不透明的情况。
@Override
protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "【 " + TAG + " 】:onCreate---");
// 在 super.onCreate(savedInstanceState) 之前调用该方法
initSwipeBackFinish();
super.onCreate(savedInstanceState);
ActivityManager.getInstance().setCurrentActivity(this);
BBApp.addActivity(this);
// 隐藏状态栏
if (getFullScreen()) {
int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
this.getWindow().setFlags(flag, flag);
}
// 获取layoutId
int layoutId = getLayoutId();
if (layoutId != 0) {
// 初始化
initialize();
// 设置布局
setContentView(layoutId);
// ButterKnife初始化
ButterKnife.bind(this);
// 删除窗口背景
getWindow().setBackgroundDrawable(null);
// 初始化数据
initData();
// 初始化视图组件
initView();
// 初始化事件
setListener();
}
//状态栏透明化: 侵入式透明status bar
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 (SharedPreferenceManager.getIsNight(this)) {
isNight = true;
} else {
isNight = false;
}
}
优点为:
使用fitSystemWindows属性让系统帮我们自动适配不同情况下的status bar,让我们的view的paddingTop获取到一个合理的值。
缺点为:就是在4.3版本及以下版本的状态栏状态栏status bar区域背景不是透明色,为黑色。
下面第二种方式在4.4版本以下状态栏一直保持为透明色
未完待续~~~~~