fitSystemWindows 以编程方式实现状态栏透明度

fitSystemWindows programmatically for status bar transparency

我的应用程序有一个 activity 为每个部分托管不同的片段。我最近通过将 fitSystemWindows 设置为 true 将状态栏设置为半透明,这已将其设置为应用程序的背景颜色。这对于具有工具栏的片段来说很好,颜色匹配,如下所示:

但是我的一个片段有照片和半透明的工具栏,所以我想让照片也占据状态栏的 space,而不是背景颜色。

我认为解决方案是仅针对该片段将 fitSystemWindows 设置为 false,然后手动向半透明工具栏添加填充。以编程方式执行此操作似乎没有效果,我做错了什么?

这是我的主要 activity 布局:

<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 toolbar -->

</RelativeLayout>

然后从我片段的 onCreateView() 中:

RelativeLayout daddyLayout = (RelativeLayout)getActivity().findViewById(R.id.main_parent_view);
daddyLayout.setFitsSystemWindows(false);
daddyLayout.invalidate();

这个好像没有效果,像这样:

如果我在 main_parent_view 中将 fitSystemWindows 设置为 false,状态栏填充将消失并且有效,但显然 影响每个片段

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

您可以使用 CoordinatorLayout 作为您的 activity 根视图,然后 setFitsSystemWindows(boolean) 将起作用。

这是因为,如本 blog post 中所述,DrawerLayoutCoordinatorLayout 对于 fitsSystemWindows 如何应用于它们都有不同的规则 - 它们都使用它来插入他们的 child 视图,但也在每个 child 上调用 dispatchApplyWindowInsets(),允许他们访问 fitsSystemWindows="true" 属性.

这与 FrameLayout 等布局的默认行为不同,其中当您使用 fitsSystemWindows="true" 时会消耗所有插图,盲目应用填充而不通知任何 child 视图(即博客的 'depth first' 部分 post).

我已经在 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);
}

好吧,你在那里处于两难境地,因为一方面你需要应用插图(因为 Toolbar 应该正确填充),另一方面你不应该 应用插图(因为你想 ImageView 在状态栏下绘制)。

事实证明,框架为这种情况提供了一个很好的 API:

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

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

但是,有问题

问题是您的根布局是 RelativeLayout,它不会向其子级发送任何关于插图的信息。它的兄弟布局也没有(LinearLayoutFrameLayout)。

如果您有 "materialish" 布局(CoordinatorLayoutDrawerLayout)之一作为根布局,那么子级将被分派那些 window 插图。

另一种选择是继承 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;
}

您可以查看 以获得与您完全相同的要求的详细说明。

简单地说

 View decorView = getActivity().getWindow().getDecorView();
    decorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

状态栏颜色使用:

getActivity().getWindow().setBackgroundDrawableResource(R.color.green);