Android 将App的内容延伸到状态栏/导航栏

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/dahaohan/article/details/52175190

看过Android的桌面应用都是介样的:

如何让自己的应用也达到这般效果呢?这里就介绍几种常用的方法以及它们之间的区别。

首先展示下此次demo的布局和初始状态:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.jokerlee.androidlsample.MainActivity"
    android:background="@android:color/holo_green_dark"
    android:fitsSystemWindows="true">


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:text="Hello World."/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="Hello World."/>

</RelativeLayout>

初始效果图如下:

透明状态栏/导航栏

使用这个方式首先要理解几个概念,窗口层级以及窗口background/窗口透明:
Google在API-19 以及API-21新增对状态栏/导航栏窗口透明和颜色的控制:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
      getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
getWindow().setStatusBarColor(blackColor);
getWindow().setNavigationBarColor(blackColor);

对应的在主题内即可控制:

        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:navigationBarColor">@android:color/transparent</item>
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">true</item>

这里首先要明了这里状态栏和导航栏窗口是系统级窗口而Activity对应的时应用窗口,它们属于不同的窗口层级;
然后状态栏/导航栏系统级窗口是在App应用窗口之上,故而Activity应用窗口虽然有整个屏幕的大小,但是可显示内容的区域得除去其上叠加的不透明的窗口区域。详细的窗口计算绘制可参考大神老罗的博文:
Android窗口管理服务WindowManagerService计算Activity窗口大小的过程分析

下面来使用主题控制导航栏/状态栏透明,同时看看上述两种设置透明的方式效果有何不同:

    <style name="TestTheme" parent="android:Theme.Material.NoActionBar">
        <!--下列两行控制使得应用窗口透明,用于展示一些差异-->
        <item name="android:windowBackground">@color/transparent</item>
        <item name="android:windowIsTranslucent">true</item>
        <!--设置导航栏/状态栏窗口color为透明-->
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:navigationBarColor">@android:color/transparent</item>

        <!--<item name="android:windowTranslucentStatus">true</item>-->
        <!--<item name="android:windowTranslucentNavigation">true</item>-->
    </style>

初始桌面和启动Activity效果图:

可以看到虽然导航栏/状态栏透明了,当时应用窗口显示的内容依然只是除去了两个系统窗口之外的区域,并没有衍生到导航栏/状态栏之下。

    //若是使用window flag控制导航栏/状态栏透明
    <style name="TestTheme" parent="android:Theme.Material.NoActionBar">

        <!--下列两行控制使得应用窗口透明,用于展示一些差异-->
        <item name="android:windowBackground">@color/transparent</item>
        <item name="android:windowIsTranslucent">true</item>
        <!--设置导航栏/状态栏窗口color为透明-->
        <!--<item name="android:statusBarColor">@android:color/transparent</item>-->
        <!--<item name="android:navigationBarColor">@android:color/transparent</item>-->

        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">true</item>
    </style>

效果如下:

可以看到已经将应用的内容布局延伸到导航栏/状态栏下方了,来看看关于android:windowTranslucentStatus
android:windowTranslucentNavigation的官方说明看看来理解其与设置color transparent的区别:

/**
Window flag: request a translucent status bar with minimal system-provided background protection.
This flag can be controlled in your theme through the {@link android.R.attr#windowTranslucentStatus} attribute; this attribute is automatically set for you in the standard translucent decor themes such as 
{@link android.R.style#Theme_Holo_NoActionBar_TranslucentDecor},
{@link android.R.style#Theme_Holo_Light_NoActionBar_TranslucentDecor},
{@link android.R.style#Theme_DeviceDefault_NoActionBar_TranslucentDecor}, and
{@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_TranslucentDecor}.

When this flag is enabled for a window, it automatically sets the system UI visibility flags {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
{@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
**/
public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;


/**
When this flag is enabled for a window, it automatically sets the system UI visibility flags {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
{@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
**/
public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;

根据FLAG的说明,可以看出设置该标志位等同于View申请设置:

//使得布局延伸到状态栏和导航栏区域
       window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

//透明状态栏/导航栏
window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarColor(Color.TRANSPARENT);
//这样的效果跟上述的主题设置效果类似

PS:从效果图看,虽然布局延伸到状态栏导航栏区域,但是相应的内容“hello world”文字也被状态栏/导航栏遮住了。在布局根视图设置fitsSystemWindows为true可以使得,系统自动为视图添加一个状态栏/导航栏高度的padding:

rootView.setFitsSystemWindows(true);
//或者xml view标签加入
android:fitsSystemWindows="true"

效果如下:

查看SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN的说明,可以发现其实还有两个非常接近的FLAG:

public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004;
public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002;
//这两flag跟上述主要区别在于,在设置和取消flag时,会引起重新布局,也就是当从SYSTEM_UI_FLAG_FULLSCREEN模式
//退出时,activity的内容显示窗口会变小,看起来就是这个布局内容画面会上移/下移。

根据官方的说明提示,SYSTEM_UI_FLAG_FULLSCREEN / SYSTEM_UI_FLAG_HIDE_NAVIGATION主要用于动态切换隐藏/显示系统导航栏/状态栏;例如书籍阅读应用/视频播放应用等。而像游戏类的全屏应用则推荐使用window flag。

API-19以下的如何实现?

上述的透明导航栏/状态栏等API基本是需要API-19或是API-21才能使用的,这里还有一种API-1的方案能够实现布局内容全屏:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);

getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);

实际上只需要设置FLAG_LAYOUT_NO_LIMITS就足够了;这FLAG是看Android原生的Launcher / Keyguard源码,看到有用到如此设置,其窗口设置具体原理我也没有弄清….. 有大神了解可以指点下。

PS:这个套路下,使用fitsSystemWindows=”true”是无效的,只能自己控制好布局位置。

猜你喜欢

转载自blog.csdn.net/dahaohan/article/details/52175190
今日推荐