Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fitSystemWindows programmatically for status bar transparency

My app has one activity that hosts different fragments for each section. I have recently made the status bar translucent by setting fitSystemWindows to true, which has set it to the background colour of the app. This is fine for fragments that have a toolbar, where the colours match, like so:

enter image description here

However one of my fragments has a photo and a translucent toolbar, so I'd like to have the photo occupy the space of the status bar too, rather than the background colour.

I believe the solution is to set fitSystemWindows to false for that fragment only, and manually add padding to the translucent toolbar. Doing this programmatically seems to have no effect, what could I be doing wrong?

Here is my main activity layout:

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

And from within my fragment's onCreateView():

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

This seems to have no effect, like so:

enter image description here

If I set fitSystemWindows to false in the main_parent_view, the status bar padding is gone and it works but obviously affects every fragment.

like image 541
Daniel Wilson Avatar asked Feb 07 '15 20:02

Daniel Wilson


2 Answers

Well, you are in dilemma situation there, because from one hand you need to apply insets (because Toolbar should be correctly padded), and on the other hand you should not apply insets (because you want ImageView to be drawn under status bar).

Turns out there's a nice API provided by the framework for that case:

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

Assuming your root layout has android:fitsSystemWindows="true", now appropriate insets would be applied to your Toolbar only, and not the ImageView.

But, there's a problem.

The problem is that your root layout is RelativeLayout, which doesn't dispatch its children any information about insets. Neither do its sibling layouts (LinearLayout, FrameLayout).

If you had as a root layout one of "materialish" layouts (CoordinatorLayout, DrawerLayout), then children would be dispatched those window insets.

The other option is to subclass RelativeLayout and dispatch WindowInsets to children manually.

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

You can see this answer for a detailed explanation with precisely same requirement you have.

enter image description here

like image 127
azizbekian Avatar answered Sep 20 '22 03:09

azizbekian


I have resolve this question in 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);
}
like image 7
Kejie Yuan Avatar answered Sep 19 '22 03:09

Kejie Yuan