fitSystemWindows以编程方式显示状态栏透明度

Dan*_*son 12 android android-layout android-fragments android-view android-styles

我的应用程序有一个活动,每个部分都有不同的片段.我最近通过设置fitSystemWindows为状态栏半透明,将true其设置为应用程序的背景颜色.这适用于具有工具栏的片段,颜色匹配,如下所示:

在此输入图像描述

然而,我的一个片段有一张照片和一个半透明的工具栏,所以我想让照片占据状态栏的空间,而不是背景颜色.

我认为,解决的办法是设置fitSystemWindowsfalse了只有片段,并手动添加填充到半透明的工具栏.以编程方式执行此操作似乎没有任何效果,我可能做错了什么?

这是我的主要活动布局:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_parent_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:fitsSystemWindows="true">

<!-- Container for various fragment layouts, including nav drawer and tool bar -->

</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

从我的片段的onCreateView()中:

RelativeLayout daddyLayout = (RelativeLayout)getActivity().findViewById(R.id.main_parent_view);
daddyLayout.setFitsSystemWindows(false);
daddyLayout.invalidate();
Run Code Online (Sandbox Code Playgroud)

这似乎没有效果,如下:

在此输入图像描述

如果我在中设置fitSystemWindows为false main_parent_view,状态栏填充消失了它可以工作,但显然会影响每个片段.

azi*_*ian 12

那么,你是在那里左右为难的境地,因为一方面你需要申请插图(因为Toolbar要正确填充),而在另一方面,你应该适用的插图(因为你想ImageView在状态栏绘制).

事实证明,该案例框架提供了一个很好的API:

ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, insets) -> {
    ((ViewGroup.MarginLayoutParams) v.getLayoutParams()).topMargin =
            insets.getSystemWindowInsetTop();
    return insets.consumeSystemWindowInsets();
});
Run Code Online (Sandbox Code Playgroud)

假设你的根布局有android:fitsSystemWindows="true",现在适当的插图将应用于你的Toolbar 唯一,而不是ImageView.

但是,有一个问题.

问题是您的根布局是RelativeLayout,它不会向子代发送有关insets的任何信息.它的兄弟布局(LinearLayout,FrameLayout)也没有.

如果您将根布局作为"物质化"布局(CoordinatorLayout,DrawerLayout)之一,则会向子节点分派这些窗口插件.

另一种选择是手动子类化RelativeLayout和分派WindowInsets给子项.

@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
    int childCount = getChildCount();
    for (int index = 0; index < childCount; index++)
        getChildAt(index).dispatchApplyWindowInsets(insets); // let children know about WindowInsets

    return insets;
}
Run Code Online (Sandbox Code Playgroud)

您可以通过完全相同的要求查看此答案以获得详细说明.

在此输入图像描述


Kej*_*uan 7

我已经在4.4中解决了这个问题

if(test){
    Log.d(TAG, "fit true ");
    relativeLayout.setFitsSystemWindows(true);
    relativeLayout.requestFitSystemWindows();
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}else {
    Log.d(TAG, "fit false");
    relativeLayout.setFitsSystemWindows(false);
    relativeLayout.requestFitSystemWindows();
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*ohn 5

您可以使用 aCoordinatorLayout作为您的活动根视图,然后setFitsSystemWindows(boolean)就可以使用了。

这是因为,在本作解释的博客帖子DrawerLayoutCoordinatorLayout都对如何不同的规则fitsSystemWindows适用于他们-他们都使用它来插页他们的孩子的意见,但也呼吁dispatchApplyWindowInsets()对每个孩子,让他们获得了fitsSystemWindows="true"财产。

这与布局的默认行为不同,例如FrameLayout当您使用时fitsSystemWindows="true"消耗所有插图,盲目应用填充而不通知任何子视图(这是博客文章的“深度优先”部分)。


vki*_*ins 3

看到同样的问题.通过从活动声明中删除fitSystemWindows并将paddingTop添加到片段,解决了我在我的应用程序中的问题.显然不是一个理想的解决方案,但似乎工作.