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

时间:2015-02-07 20:57:49

标签: android android-layout android-fragments android-view android-styles

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

enter image description here

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

我认为解决方案是仅为该片段设置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>

从我的片段中的onCreateView():

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

这似乎没有效果,如下:

enter image description here

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

5 个答案:

答案 0 :(得分:11)

那么,你处于两难境地,因为一方面你需要应用插图(因为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)也没有。

如果您拥有&#34;物质化的&#34;布局(CoordinatorLayoutDrawerLayout),然后将子项发送给那些窗口插件。

另一个选项是子类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;
}

您可以看到this answer的详细说明,但要求与您完全相同。

enter image description here

答案 1 :(得分: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);
}

答案 2 :(得分:4)

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

答案 3 :(得分:4)

您可以使用Z作为活动根视图,然后CoordinatorLayout即可使用。

这是因为,正如blog post中所述,setFitsSystemWindows(boolean)DrawerLayoutCoordinatorLayout如何适用于他们有不同的规则 - 他们都使用它来插入他们的子视图,但也为每个孩子调用fitsSystemWindows,允许他们访问dispatchApplyWindowInsets()属性。

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

答案 4 :(得分:0)

简单地放置

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