Android中实现侵入式状态栏的两种方式

最近对“爸比讲故事”Android版本进行代码重构的时候,对之前版本的大部分界面的头部侵入式效果,作了一个总结和梳理,在期间查阅了thinkcool的博客和结合亲身实践,总结了2种侵入式实现的不同思路:

两种方式都会使用到Android的一个属性:fitsSystemWindows

第一种:不添加view覆盖status bar的方式,在Toolbar控件上添加fitSystemWindows属性为true

首先来看看这种方式在不同版本手机的表现方式

1、Android SDK 4.3(level 18)以下的表现效果为:APP 的内容不被上拉到状态,不占据status bar,不透明效果


不占据status bar

2、Android SDK 5.1 (level 22)华为畅享5s的表现效果为:占据status bar,全透明效果


占据status bar

3、Android SDK 5.1 (level 22)vivio手机的表现效果为:status bar半透明效果


占据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版本以下状态栏一直保持为透明色

                                    未完待续~~~~~
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,875评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,569评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,475评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,459评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,537评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,563评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,580评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,326评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,773评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,086评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,252评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,921评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,566评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,190评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,435评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,129评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,125评论 2 352

推荐阅读更多精彩内容