Display DialogFragment content below status bar

Bugdr0id picture Bugdr0id · Sep 28, 2017 · Viewed 8.6k times · Source

Im trying to display an DialogFragment with match_parent both for height and width but it happens that on top the DialogFragment is being displayed below StatusBar.

The DialogFragment is applying some default value for padding on bottom, right, left, and top. But the top padding should start counting from statusBar and not from the total screen size.

How can I set DialogFragment to be match_parent, but have the normal/default padding on top,bottom,right,left?

Answer

azizbekian picture azizbekian · Sep 28, 2017

By default Dialog would be applied FLAG_LAYOUT_IN_SCREEN and FLAG_LAYOUT_INSET_DECOR flags. An excerpt from PhoneWindow:


        mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
                & (~getForcedWindowFlags());
        if (mIsFloating) {
            setLayout(WRAP_CONTENT, WRAP_CONTENT);
            setFlags(0, flagsToUpdate);
        } else {
            setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
        }

FLAG_LAYOUT_INSET_DECOR is the flag, that you do not want to be applied. From docs:

Window flag: a special option only for use in combination with FLAG_LAYOUT_IN_SCREEN. When requesting layout in the screen your window may appear on top of or behind screen decorations such as the status bar. By also including this flag, the window manager will report the inset rectangle needed to ensure your content is not covered by screen decorations. This flag is normally set for you by Window as described in setFlags(int, int).

By default, windowIsFloating is enabled. So, if you declare your custom theme:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    ...
    <item name="android:windowTranslucentStatus">true</item>
    <item name="android:windowTranslucentNavigation">true</item>
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>

</style>

<style name="MyTheme" parent="@style/ThemeOverlay.AppCompat.Dialog.Alert">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:colorBackgroundCacheHint">@null</item>
    <item name="android:windowFrame">@null</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowAnimationStyle">@null</item>
    <item name="android:windowIsFloating">false</item>
    <item name="android:backgroundDimEnabled">false</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowNoTitle">true</item>
</style>

Then in your DialogFragment:


    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = new Dialog(getActivity(), R.style.MyTheme);
        dialog.setContentView(R.layout.your_layout);
        return dialog;
    }

Where the layout content is following:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <View
        android:layout_gravity="center_horizontal"
        android:background="@color/colorAccent"
        android:layout_width="250dp"
        android:layout_height="700dp"/>

</FrameLayout>

Then you'll get this output:


If you want the pink layout to be laid out below status bar and above navigation bar, then just apply android:fitsSystemWindows="true" to your root ViewGroup:

<FrameLayout
    ...
    android:fitsSystemWindows="true">

    <View .../>

</FrameLayout>

This will be the output:

You can see the meaning of that flag in my this answer.