沉浸式状态栏那些事儿

一、什么是沉浸式状态栏

首先请让我们看看没有使用沉浸式的效果:

上面这张图是没有使用沉浸式的美团外卖,我们可以看到最上面的黑色的那一条就是状态栏,大部分android默认是黑色底,白色字。

好了,下面让我祭出使用了沉浸式以后的效果图:

说回来吧,状态栏(系统)跟我们的app的标题栏的颜色融为一体,非常美观大方得体。而这样就是我今天要介绍的效果。

  • 这里需要注意的的是:ISO很早以前原生就支持了沉浸式状态栏,但是android要到API 19以上才有了支持,也就是说,API 19以下的手机是不能兼容的。如果你们的项目经理叫你们去适配API 19以下的手机,那你就可以告诉他唯一的解决的办法就是要用户去买一台API 19以上的手机,哈哈!

为了能够和ISO尽量统一风格,为了更加美观大方,我们还是有必要学习一下沉浸式的实现方法。

二、沉浸式状态栏的实现方式

方式1:布局的内容不进入状态栏

这种方法主要是通过GitHub上面的一个开源库实现,下面让我原汁原味贴出项目的源码:

//需要引入的类库
compile 'com.readystatesoftware.systembartint:systembartint:1.0.4'

import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import com.readystatesoftware.systembartint.SystemBarTintManager;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 设置状态栏颜色的工具类
 */
public class TintBarUtils {

    /**
     * 设置activity的状态栏颜色,注意需要在activity的布局当中添加属性:android:fitsSystemWindows="true"
     *
     * @param activity
     * @param statusBarTintColor
     */
    public static void setStatusBarTintColor(Activity activity, int statusBarTintColor) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            setTranslucentStatus(true, activity);
            SystemBarTintManager mTintManager = new SystemBarTintManager(activity);
            mTintManager.setStatusBarTintEnabled(true);
            mTintManager.setNavigationBarTintEnabled(true);
            mTintManager.setTintColor(statusBarTintColor);

            setStatusBarTextStyle(activity, true);
        }
    }

    public static void setStatusBarTextStyle(Activity activity, boolean lightMode) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (lightMode) {
                activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            }
        } else {
            MIUISetStatusBarLightMode(activity.getWindow(), lightMode);
            FlymeSetStatusBarLightMode(activity.getWindow(), lightMode);
        }
    }

    @TargetApi(19)
    private static void setTranslucentStatus(boolean on, Activity activity) {
        Window win = activity.getWindow();
        WindowManager.LayoutParams winParams = win.getAttributes();
        final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
        if (on) {
            winParams.flags |= bits;
        } else {
            winParams.flags &= ~bits;
        }
        win.setAttributes(winParams);
    }

    @TargetApi(19)
    public static void hideStatusBar(Activity activity) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

            setTranslucentStatus(false, activity);

            SystemBarTintManager mTintManager = new SystemBarTintManager(activity);
            mTintManager.setStatusBarTintEnabled(false);
            mTintManager.setNavigationBarTintEnabled(false);

            Window win = activity.getWindow();
            WindowManager.LayoutParams winParams = win.getAttributes();
            final int bits = WindowManager.LayoutParams.FLAG_FULLSCREEN;
            winParams.flags &= ~bits;
            win.setAttributes(winParams);
        }
    }

    /**
     * 设置状态栏图标为深色和魅族特定的文字风格 * 可以用来判断是否为Flyme用户 * @param window 需要设置的窗口 * @param dark 是否把状态栏字体及图标颜色设置为深色 * @return boolean 成功执行返回true *
     */
    public static boolean FlymeSetStatusBarLightMode(Window window, boolean dark) {
        boolean result = false;
        if (window != null) {
            try {
                WindowManager.LayoutParams lp = window.getAttributes();
                Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
                Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
                darkFlag.setAccessible(true);
                meizuFlags.setAccessible(true);
                int bit = darkFlag.getInt(null);
                int value = meizuFlags.getInt(lp);
                if (dark) {
                    value |= bit;
                } else {
                    value &= ~bit;
                }
                meizuFlags.setInt(lp, value);
                window.setAttributes(lp);
                result = true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 设置状态栏字体图标为深色,需要MIUIV6以上
     *
     * @param window 需要设置的窗口
     * @param dark   是否把状态栏字体及图标颜色设置为深色
     * @return boolean 成功执行返回true
     */
    public static boolean MIUISetStatusBarLightMode(Window window, boolean dark) {
        boolean result = false;
        if (window != null) {
            Class clazz = window.getClass();
            try {
                int darkModeFlag = 0;
                Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
                Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
                darkModeFlag = field.getInt(layoutParams);
                Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
                if (dark) {
                    extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体 }else{ extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体 } result=true; }catch (Exception e){ } } return result; }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

}

这里需要特别强调一点就是activity布局文件中的跟布局必须有下面这个属性,否则我们的设置是没有效果的:

android:fitsSystemWindows="true"

我们要关注的核心方法是setStatusBarTintColor,这个方法需要传入一个Activity对象,以及颜色值,即可设置状态栏的颜色。需要注意的是这个方法需要判断当前的API版本是不是大于19才能使用。至于具体的实现,大家可以仔细看源码。这里只强调如何快速使用到你的项目当中。

但是这里有一个尴尬的问题就是:当我们的APP标题栏是白色的时候,例如上面的第二张图,如果我们设置了白色的状态栏,那么状态辣女白色的文字将会看不到。解决的办法比较棘手,我当时也是懵逼了好久,在项目经理的重压之下还是找到了解决方案。在android M也就是API23以上,google官方提供了设置状态栏文字风格的方法:

activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

为了向下兼容,小米和魅族两个品牌由于深度定制过android的ROM,都提供了通过反射的方式是改变状态栏的文字颜色。他们分别是:
MIUISetStatusBarLightMode和FlymeSetStatusBarLightMode,通过传入的参数dark为true就可改变状态栏文字颜色,至于怎么改变,大家可以亲自尝试一下,这里不再啰嗦。

方式2:布局的内容进入状态栏

如上面第三张图所示,我们的contentView进入了状态栏,这又是怎么实现的呢?其实很简单,只要把我们的布局延伸到状态栏,并且添加一个高度为状态栏高度的View(status_bar_top)或者上Padding即可。

protected int statusBarHeight;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    immerseLayout();
}

protected void immerseLayout() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        Window window = getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        statusBarHeight = getStatusBarHeight(this.getBaseContext());
        viewStatusBarTop = findViewById(R.id.status_bar_top);
        RelativeLayout.LayoutParams params2 = (RelativeLayout.LayoutParams) viewStatusBarTop.getLayoutParams();
        params2.height = statusBarHeight;
        viewStatusBarTop.setLayoutParams(params2);
        viewStatusBarTop.setVisibility(View.VISIBLE);
    }
}

public int getStatusBarHeight(Context context) {
    if (statusBarHeight != 0)
        return statusBarHeight;

    int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
    }
    return statusBarHeight;
}

下面给出这个activity的布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="false">

    <View
        android:id="@+id/status_bar_top"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_alignParentTop="true"
        android:background="@drawable/status_bar"
        android:visibility="gone" />

    。。。这里是我们的布局         

</RelativeLayout>

今天的项目笔记就到这里了,有什么问题欢迎通过以下方式联系我:
QQ(微信):1435378192,楠总or小楠
android学习交流群:459355901

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值