Welcome to pay attention to the wechat public account “Conveniently Record Technical Team”, check out more technical articles of conveniently Record team. Author: Liu Ling Link: mp.weixin.qq.com/s/d6D_rYmzl…

1 – introduction

As for the term “immersive status bar”, some friends may find it inappropriate. But most of the talking on the Internet “immersive status bar” generally refers to the “transparent status bar”, so it won’t discuss its right or wrong, in fact, sometimes wrong many, also became the), as we all know is said “transparent status bar”, below are all call this effect “immersive status bar”.

Before Android 4.4, there was no way to set the background color of the status bar for any app. The background color of the status bar followed the system (black background status bar), and a black status bar was very incompatible with the application. To provide better interaction, Google has provided a way to set up an immersive status bar since Android 4.4. Apps that support an immersive status bar tend to have a slightly higher interface, so keep in mind that Android clients also supported an immersive status bar earlier this year. For the record, I stomped a lot of holes in the process of implementing the immersive status bar effect. The following picture shows the comparison of the effect before and after setting the immersive status bar on the Android client:

Comparing the two effects, it is clear that the immersive status bar below looks more harmonious and beautiful.

2- How to implement an immersive status bar

2.1-Android 4.4 above implementation methods

Since the immersive status bar wasn’t available until After Android 4.4, we need to adapt to Android 4.4 and beyond. Android 4.4 has two ways to implement an immersive status bar, either in a resource file or in code.

2.1.1- Set the immersive status bar in resource files

First, we need to modify values/styles.xml to add an empty style that inherits from the BaseTheme.

<resources> <! -- Base application theme. --> <style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar"> <! -- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="AppTheme" parent="BaseTheme" />
</resources>
Copy the code

Then add the following code to the styles. XML file in the values-v19 directory (if you don’t have a new one in your project, systems up to 4.4 will read the resource file in this directory) :

<resources>
    <style name="AppTheme" parent="BaseTheme">
        <item name="android:windowTranslucentStatus">true</item>
    </style>
</resources>
Copy the code

Then set your App’s theme to AppTheme. Note: the android: started introducing v19 windowTranslucentStatus this attribute.

2.1.2- Set in code

To make it easier to implement in code, simply add a flag for FLAG_TRANSLUCENT_STATUS to BaseActivity.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
Copy the code

After setting by the above two methods, the effect picture is as follows:

We’ll see that the Toolbar pops into the status bar simply by setting it above. A common thought is to use the fitsSystemWindows property to solve this problem.

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. Brief description: This property allows the view to adjust its layout based on system Windows such as the Status bar. If true, The view’s paingding property is adjusted to make room for System Windows (adding a top padding value of the status bar height to the view).

Let’s try setting the fitsSystemWindows property to True for the Toolbar. The layout code is as follows:

<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
 
    <android.support.v7.widget.Toolbar
        android:id="@+id/my_toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:minHeight="? attr/actionBarSize"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
 
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:padding="16dp">
 
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#e0e0e0"
            android:layout_gravity="bottom">
            <EditText
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:fitsSystemWindows="true"
                android:background="@drawable/edit_text_rect_bg" />
        </RelativeLayout>
    </FrameLayout>
</LinearLayout>
Copy the code

Android 4.4 and Android 5.0+

As you can see from the comparison above, on Android 4.4 the status bar is completely transparent, while on Android 5.0+ the status bar is translucent.

Note: On some 4.4 systems, the status bar is not fully transparent, but gradient.

2.2- Implementation of Android 5.0 above

The immersive status bar is already available, but running on Android 5.0 or higher, most phones will have a semi-transparent status bar.

There are also some apps in Android 5.0 above the status bar translucent effect, such as QQ. But some products and designs just want to be the same, and all have transparent status bars. So what to do? Since 5.0, Android has provided an API for setting the color of the status bar. We can set the color of the status bar ourselves.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    window.setStatusBarColor(Color.TRANSPARENT);
 
}
Copy the code

After adding the above code and running it on Android 5.0+, the status bar has become completely transparent. It has the same effect as Android 4.4 above.

2.3-Android 6.0 above set the status bar font color

By default, most phones use white text in the status bar. If the Toolbar or header is light, the white text on the status bar will be hard to read. After Android 6.0, we can set the status bar font color to black using the following code:

window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
Copy the code

3- Stomped pits

I thought the immersive status bar was almost perfect, but when I tested it, I found a series of bugs.

3.1- The Toolbar is jacked up when the soft keyboard pops up

If you have an EditText or other input box in the interface, you’ll see that the contents of the Toolbar are topped up when the dashboard pops up, as shown below:

Why is that? It turns out that the fitsSystemWindows property is the culprit. Any View with fitsSystemWindows= True will be overridden by the software disk. So, fitsSystemWindows can not be used randomly, there will be unexpected pit. How about not using fitsSystemWindows? B: Sure. FitsSystemWindows = True adds the padding of the status bar height to the View, so why not add the padding to the Toolbar manually? We remove the fitsSystemWindows property on the Toolbar and set the padding on the Toolbar as follows:

protected void setStatusBarPaddingAndHeight(View toolBar) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        if(toolBar ! = null) { int statusBarHeight = getSystemBarHeight(this); toolBar.setPadding(toolBar.getPaddingLeft(), statusBarHeight, toolBar.getPaddingRight(), toolBar.getPaddingBottom()); toolBar.getLayoutParams().height = statusBarHeight + (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 45, getResources().getDisplayMetrics()); }}}Copy the code

Remove the Toolbar’s fitsSystemWindows attribute and add the above code, and the Toolbar works when the soft keyboard pops up. The current Android project uses code to add padding instead of fitsSystemWindows.

3.2- Input fields such as EditText will be overwritten by software disk when the soft keyboard pops up

In the example above, where the Toolbar is pushed up, the EditText is overwritten by the soft keyboard instead of popping up.

The fitsSystemWindows attribute adds to the Toolbar to be overwritten by the keyboard. Will adding a fitsSystemWindows attribute to the input box solve the problem? Give it a go!

It works, but the height of the input box has changed. The padding of the input box increases the height of the status bar. Obviously, this is not a very good solution. A solution was later found on StackOverflow: a solution to FLAG_TRANSLUCENT_STATUS causing the input box to be overwritten by a soft keyboard

We’ve tweaked it a bit, and the code looks like this:

public class AndroidBug5497Workaround {

    public static void assistActivity(View content) {
        new AndroidBug5497Workaround(content);
    }

    private View mChildOfContent;
    private int usableHeightPrevious;
    private ViewGroup.LayoutParams frameLayoutParams;

    private AndroidBug5497Workaround(View content) {
        if(content ! = null) { mChildOfContent = content; mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                public void onGlobalLayout() { possiblyResizeChildOfContent(); }}); frameLayoutParams = mChildOfContent.getLayoutParams(); } } private voidpossiblyResizeChildOfContent() {
        int usableHeightNow = computeUsableHeight();
        if(usableHeightNow ! = usableHeightPrevious) {// If the two heights are inconsistent // Set the calculated visual height to the view height framelayOutparams. height = usableHeightNow; mChildOfContent.requestLayout(); UsableHeightPrevious = usableHeightNow; } } private intcomputeUsableHeightRect r = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(r);returnr.bottom; }}Copy the code

Add the above class and add the following code to the setContentView in the Activity’s onCreate method:

AndroidBug5497Workaround.assistActivity(findViewById(android.R.id.content));
Copy the code

Then run, the input box can be normally up, and the layout of the input box is not affected.

The idea is to set up a listener for the root layout of the interface. When the size of the interface changes, such as when the keyboard pops up, reset the height of the root layout, and then call requestLayout to redraw the interface.

At present, I remember that Android is using this scheme, and so far I have not found any other problems caused by this scheme.

3.3- pit on huawei EMUI3.1

Run the above immersive code on a mobile phone with EMUI3.1 system (such as Huawei Honor 7), and you will find no immersive effect at all. The status bar is transparent, showing the color of the desktop, as shown below:

It has been proved that the original reason is the EMUI3.1 system. Many apps also have an immersive effect on EMUI3.0, but no effect on EMUI3.1. It doesn’t matter if EMUI3.1 doesn’t have the same immersion effect as before 4.4, so transparent display of desktop color is ugly. It turned out that by removing the following code, it could have an immersive effect.

window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
Copy the code

The effect is as follows:

Instead of being completely transparent, the status bar has a gradient like on some 4.4 systems, but it’s better than displaying desktop colors. FLAG_TRANSLUCENT_STATUS is cleared by clearFlags if it is not an EMUI3.1 system. The specific code is as follows:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
   Window window = getWindow();
   window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
   if(build.version.sdk_int >= build.version_codes.lollipop) {// Because the EMUI3.1 system conflicts with this immersive scheme API, there will be no immersive effect. // EMUI3.1 does not clear FLAG_TRANSLUCENT_STATUSif(! isEMUI3_1()) { window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); } } public static booleanisEMUI3_1() {
    if ("EmotionUI_3. 1".equals(getEmuiVersion())) {
        return true;
    }
    return false;
}
 
private static String getEmuiVersion(){ Class<? > classType = null; try { classType = Class.forName("android.os.SystemProperties");
        Method getMethod = classType.getDeclaredMethod("get", String.class);
        return (String)getMethod.invoke(classType, "ro.build.version.emui");
    } catch (Exception e){
    }
    return "";
}
Copy the code

3.4-CoordinatorLayout+AppBarLayout Scroll hide navigation bar encountered immersive status bar pit

This pit is mainly in the need to do financial headlines encountered.

Background: The toutiao function needs to realize two levels of TabLayout navigation, the first level is the Toolbar (Headline, Product and Discovery), the second level is the TabLayout that switches each column in the toutiao. What you need to achieve is that in the Headline Fragment, sliding the post list hides and shows the first level navigation Toolbar. When the first navigation Toolbar is displayed, swiping left or right toggles the first navigation tabs (headlines, Discovery, and Products). After scrolling up and down the post list in the Header Fragment to hide the first navigation Toolbar, swiping left and right toggles the second navigation TAB. The effect is shown below.

The first thing that comes to mind when scrolling to hide and show toolbars is CoordinatorLayout+AppBarLayout. Add and modify the layout of the Activity based on the immersive effects already implemented in the project:

<android.support.design.widget.CoordinatorLayout
   android:id="@+id/coordinator_layout"
   android:layout_height="match_parent"
   android:layout_width="match_parent">
   <android.support.design.widget.AppBarLayout
       android:id="@+id/appbar_layout"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:elevation="0dp">
       <android.support.v7.widget.Toolbar
           android:layout_width="match_parent"
           android:layout_height="? attr/actionBarSize"
           app:contentInsetStart="0dip"
           app:contentInsetLeft="0dip"
           app:contentInsetEnd="0dip"
           app:layout_scrollFlags="scroll|enterAlways">... Some code omitted... <android.support.design.widget.TabLayout android:id="@+id/tab_layout"
              android:layout_width="wrap_content"
              android:layout_height="match_parent"
              android:layout_centerHorizontal="true"
              app:tabBackground="@null"
              app:tabIndicatorColor="@color/tab_text_selected_color"
              app:tabIndicatorHeight="2dip"
              app:tabMode="fixed"
              app:tabGravity="fill"
              app:tabPaddingStart="14dp"
              app:tabPaddingEnd="14dp"
              app:tabTextAppearance="@style/FinanceTabTextAppearance"
              app:tabSelectedTextColor="@color/tab_text_selected_color"
              app:tabTextColor="@color/tab_text_unselected_color"/> </android.support.v7.widget.Toolbar> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager  android:id="@+id/pager"
       android:layout_width="match_parent"
       android:paddingBottom="50dp"
       android:layout_height="match_parent"
       android:overScrollMode="never"
       app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
Copy the code

Layout is adding a TabLayout to the Toolbar as a TAB for level 1 navigation. Then use a ViewPager and add three fragments to the ViewPager: the Fragment for headline, product, and discovery. The header Fragment contains nested TabLayout and ViewPager. Based on the immersive implementation, add a status bar height padding to AppBarLayout in the code. I thought I was done, but after running it, I slid up to hide AppBarLayout and then pulled it down, which would exceed the drop-down range. In other words, the height of the status bar would be blank as shown at the top of the picture:

After constant trial and exploration, we found that we can add the following flag to the Activity:

this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
Copy the code

Well, good. Slide problem solved. But the heart is always uneasy, always feel pit. After adding this flag, some Huawei mobile phones with virtual buttons have the problem of virtual buttons blocking the bottom layout. It has been verified that only EMUI3.1 has this problem (again, it is EMUI3.1, which has no ability to make jokes). Finally, after all the twists and turns, we finally found a way to effectively solve the sliding problem of CoordinatorLayout+AppBarLayout and set paddingTop for AppBarLayout.

this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
Copy the code

I thought the above solution was perfect without any problems, but there are still problems. Soon after, the test found a live network problem: when the input box in the WebView to get focus soft keyboard pops up, the bottom layout of the interface when exiting the black block soft keyboard size. As shown below:

After investigation, this problem is caused by the above code. There was no choice but to remove the above code and find another solution to handle CoordinatorLayout+AppBarLayout and set paddingTop for AppBarLayout. It turns out that adding the following code to the Activity’s onCreate method solves this problem perfectly.

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.root_container_layout), new android.support.v4.view.OnApplyWindowInsetsListener() {
        @Override
       public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
            returninsets.consumeSystemWindowInsets(); }}); }Copy the code

4 –

Above is a quick reminder of the pitfalls and solutions encountered during the implementation of the immersive status bar in Android projects. Finally with Android to achieve the status bar effect in different models above the effect picture is as follows:

After the development of immersive status bar, found several easy to step on the pit need to pay attention to: 1. FitsSystemWindows =true to be careful to use, many pits. For example, in a WebView, when the input box gets the focus and the soft keyboard pops up, there will be jitter, and any View with fitsSystemWindows= True set will be pushed up when the soft keyboard pops up. 2. WindowManager. LayoutParams FLAG_LAYOUT_NO_LIMITS don’t use, can lead to system virtual buttons below EMUI3.1 block layout;

5- Reference documentation

Stackoverflow.com/questions/7…