以编程方式为系统窗口提供状态栏透明度

我的应用程序有一个活动,每个部分承载不同的片段。 我最近通过将fitSystemWindows设置为true来将状态栏fitSystemWindows半透明的,将其设置为应用程序的背景颜色。 对于具有工具栏的颜色匹配的片段来说,这样做很好:

在这里输入图像说明

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

我相信解决的办法是将fitSystemWindows设置为仅用于该片段的false ,并手动添加填充到半透明工具栏。 这样做编程似乎没有效果,我可能做错了什么?

这是我的主要活动布局:

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

并从我的片段的onCreateView():

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

这似乎没有效果,如下所示:

在这里输入图像说明

如果我在fitSystemWindows设置为false,则状态栏填充消失,并且工作正常,但显然会影响每个片段

Solutions Collecting From Web of "以编程方式为系统窗口提供状态栏透明度"

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

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

这是因为,正如本博文中所解释的那样, DrawerLayoutCoordinatorLayout对于fitsSystemWindows如何应用它们有不同的规则 – 它们都使用它来插入他们的子视图,而且还在每个子项上调用dispatchApplyWindowInsets() ,允许它们访问fitsSystemWindows="true"属性。

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

我已经在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 ,它不派遣它的子对任何关于insets的信息。 它的同级布局( LinearLayoutFrameLayout )也没有。

如果你有一个“物质”布局( CoordinatorLayoutDrawerLayout )作为根布局,那么子DrawerLayout将被分派这些窗口插入。

另一个选项是对RelativeLayout进行子类化,并手动将WindowInsetsWindowInsets子项。

 @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; } 

你可以看到这个答案的详细解释与你有完全相同的要求。

在这里输入图像说明