IT_Programming/Android_Java

FullScreen DialogFragment 의 내용이 상태바에 가려지는 증상 - Display DialogFragment content below status bar

JJun ™ 2018. 7. 19. 06:05



 * 출처

 : https://stackoverflow.com/a/46469822




전면 팝업으로 DialogFragment로 풀 스크린(FullScreen) 팝업 다이얼로그를 노출할 경우 UI가 상태바에 가려지는 현상이 발생할 수 있는데...


기본적으로 Dialog는 FLAG_LAYOUT_IN_SCREEN 및 FLAG_LAYOUT_INSET_DECOR 플래그에 적용됩니다. 

이 중 FLAG_LAYOUT_INSET_DECOR 속성 때문에 발생하는 증상으로...


이를 해결하기 위해서는 아래와 같은 과정으로 처리하면 된다.


1) Style 정의

    - 예

      <!-- Full 화면 다이얼로그 스테이터스바 관련 이슈 (WindowInset 이슈) -->

      <style name="popCasterDlgTheme" 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>


2) DialogFragment에 onCreateDialog() 메소드에서 Dialog 생성 시 위의 스타일을 적용한다.

    - 예: Dialog dialog = new Dialog(getActivity(), R.style.popCasterDlgTheme);


3) DialogFragment layout 최상단 레이아웃에 android:fitsSystemWindows="true" 속성 추가 



더 자세한 내용은 아래의 StackOverflow의 내용을 참고하면 됩니다. 





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.