沉浸式探索
目前市场上的好多应用都已经使用了沉浸式,实现方式可以有多中,其中在主题中可以设置两个属性:
//这两个属性默认都是false, //windowTranslucentStatus指的是状态栏是半透明, //当这个值为false时,可以设置statusBarColor的颜色, //当为true时,statusBarColor不起作用,内容会处于状态栏(半透明)的下面 <item name="android:windowTranslucentStatus">true</item> //windowTranslucentNavigation指的是导航栏的半透明 //当这个值为false时,可以设置navigationBarColor的颜色 //当这个值为true时,navigationBarColor不起作用,内容会处于导航栏(半透明)和状态栏下面 <item name="android:windowTranslucentNavigation">true</item> <item name="android:statusBarColor">#ff0000</item> <item name="android:navigationBarColor">#ff0000</item>
当需要把状态栏的半透明换成和底背景一样时,只需要把windowtranslucentStatus改成false或是去掉即可,这两个属性是在PhoneWindow中获取并设置的,让我们来看一下generateLayout(DecorView decor)(这个方法是在setContentView()中被调用到的)这个方法是如何设置的:
if (a.getBoolean(R.styleable.Window_windowTranslucentStatus, false)) { setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS & (~getForcedWindowFlags())); } if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation, false)) { setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION & (~getForcedWindowFlags())); }其实就是调用了Window的setFlags()方法,还有上面设置的颜色也是在这里获取的
if (!mForcedStatusBarColor) { mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000); } if (!mForcedNavigationBarColor) { mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000); }
这里获取到颜色后会在DecorView中进行设置,
private int calculateStatusBarColor() { return calculateStatusBarColor(mWindow.getAttributes().flags, mSemiTransparentStatusBarColor, mWindow.mStatusBarColor); } public static int calculateStatusBarColor(int flags, int semiTransparentStatusBarColor, int statusBarColor) { return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? semiTransparentStatusBarColor : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? statusBarColor : Color.BLACK; }
这里就是决定statusBarColor的颜色到底是哪一个。
对于这里的所有设置都可以在代码中进行设置,具体的可以查看郭霖的这一篇点击打开链接。
不管是在代码中设置还是在主题中设置,最后决定权还是在DecorView这里,
WindowInsets updateColorViews(WindowInsets insets, boolean animate) { WindowManager.LayoutParams attrs = mWindow.getAttributes(); //主题中设置的系统UI属性在这里可以获取 attrs.systemUiVisibility //代码中设置的系统UI属性在这里可以获取 getWindowSystemUiVisibility() int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility(); ... // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need // to ensure that the rest of the view hierarchy doesn't notice it, unless they've // explicitly asked for it. boolean consumingNavBar = (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0 && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0 || mLastShouldAlwaysConsumeNavBar; // If we didn't request fullscreen layout, but we still got it because of the // mForceWindowDrawsStatusBarBackground flag, also consume top inset. boolean consumingStatusBar = (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0 && (sysUiVisibility & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0 && (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0 && (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0 && mForceWindowDrawsStatusBarBackground && mLastTopInset != 0; int consumedTop = consumingStatusBar ? mLastTopInset : 0; int consumedRight = consumingNavBar ? mLastRightInset : 0; int consumedBottom = consumingNavBar ? mLastBottomInset : 0; int consumedLeft = consumingNavBar ? mLastLeftInset : 0; if (mContentRoot != null && mContentRoot.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mContentRoot.getLayoutParams(); if (lp.topMargin != consumedTop || lp.rightMargin != consumedRight || lp.bottomMargin != consumedBottom || lp.leftMargin != consumedLeft) { lp.topMargin = consumedTop; lp.rightMargin = consumedRight; lp.bottomMargin = consumedBottom; lp.leftMargin = consumedLeft; mContentRoot.setLayoutParams(lp); if (insets == null) { // The insets have changed, but we're not currently in the process // of dispatching them. requestApplyInsets(); } } if (insets != null) { insets = insets.replaceSystemWindowInsets( insets.getSystemWindowInsetLeft() - consumedLeft, insets.getSystemWindowInsetTop() - consumedTop, insets.getSystemWindowInsetRight() - consumedRight, insets.getSystemWindowInsetBottom() - consumedBottom); } } if (insets != null) { insets = insets.consumeStableInsets(); } return insets; }从这里可以看出,沉浸式其实就是根据设置的属性计算内容所占的空间大小。