[Android] status bar 투명하게 만들기 + drawer layout

문제 상황

  • 문제 상황 : 특정 프래그먼트에서 drawer layout을 사용하는데, drawer layout의 영역이 화면에 꽉차게, 상태바 위를 덮었으면 좋겠음.
  • 해결 방안 : android:fitsSystemWindows="true"와 상태바의 색상을 투명하게 만들기!
    _ 만약 상태바의 색상이 있다면, fitsSystemWindows="true"를 이용해도, drawer layout 위에 상태바 색상이 있어서 문제 상황이 계속됨.

1. themes.xml & manifest.xml 설정.

코드

*theme
  <style name="Theme.SeeMeet.TransparentStatusBar" parent="Theme.MaterialComponents.Light.NoActionBar">
        <!--drawerlayout statusbar -->
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:windowLightStatusBar">true</item>
        <item name="android:windowTranslucentStatus">true</item>
    </style>

* manifest 

 <activity
            android:name=".ui.main.MainActivity"
            android:exported="false"
    		android:theme="@style/Theme.SeeMeet.TransparentStatusBar" />

문제 상황에도 말했지만, 앱 전체적으로 투명한 상태바를 만들 필요가 없고, 특정 액티비티에만 적용되면 되는 상황이라, 투명한 상태바로 만들어주는 특정 style을 따로 선언해주고, 이를 manifest에서 사용할 activity에 적용해주었다.

theme에서 추가한 item 속성들의 의미

  1. android:windowDrawsSystemBarBackgrounds : 상태바 아래에 다른 뷰가 표시될 수 있도록 합니다. 단, 네비게이션 바 부분은 제외합니다.
  2. android:windowTranslucentStatus : 상태바 배경 색을 지정합니다.
  3. android:windowLightStatusBar : 상태바에 표시되는 글자의 색을 지정합니다. true의 경우는 검정글씨, false의 경우는 하얀 글씨로 표시됩니다.

-> 여기의 theme만 적용한다면 아마 완전히 투명한 상태바가 아니라, 아래의 사진처럼 반투명한 검정색 status bar가 적용된 것을 볼 수 있을 것이다.

2.DrawerLayout : 관련 뷰에 android:fitsSystemWindows="true" 적용하기.

참고 사이트 : https://developer.android.com/guide/navigation/navigation-ui?hl=ko

<?xml version="1.0" encoding="utf-8"?>
<!-- Use DrawerLayout as root container for activity -->
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <!-- Layout to contain contents of main body of screen (drawer will slide over this) -->
    <androidx.fragment.app.FragmentContainerView
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:id="@+id/nav_host_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

    <!-- Container for contents of drawer - use NavigationView to make configuration easier -->
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true">
      
      <include android:id="@+id/nv_mypage" layout="@layout/view_mypage"/>
      </com.google.android.material.navigation.NavigationView>

</androidx.drawerlayout.widget.DrawerLayout>

위 코드를 보면 루트의 drawerLayout과 하단의 NavigationView의 경우 fitsSystemWindows="true" 속성이 있는 것을 확인할 수 있다. 똑같이 넣어주도록 하자.

또한, 공식 페이지의 코드를 보면, navigationView에 따로 include하여 뷰를 추가해두지 않았는데, 나의 경우, navigationView에 추가할 레이아웃을 따로 만들어두었기에 이를 include하였다. < 이 경우 include한 레이아웃의 루트에도 마찬가지로 firsSystemWindows="true"를 추가해줘야한다.

fitsSystemWindows="true" 의미

상태 표시줄과 같은 시스템 창을 기반으로 보기 레이아웃을 조정하는 속성. true이면 시스템 창을 위한 공간을 남기기 위해 이 보기의 패딩을 조정한다. _ 한마디로 status bar나 navigation bar를 포함한 전체 창 크기에 맞게 레이아웃을 조정해준다.

3. kotlin코드단에 flag 추가.

2는 drawer layout 용이었고, 1에서 말한대로, theme의 투명한 상태바 만들기 코드들만 적용한다면, 검정색 반투명한 상태바가 만들어지게 된다.

원하는 것은 완전히 투명한 상태바이기 때문에 kotlin 코드를 추가해줘야한다.

//status bar와 navigation bar 모두 투명하게 만드는 코드 
window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
					WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)

최상위 창 모양 및 동작 정책에 대한 추상 기본 클래스인 window에 관련 flag를 설정해주는 코드이다. 상태바의 투명하게 보일 엑티비티의 onCreate() 단에 설정을 해주면 된다.
전체 앱에 적용을 원한다면 baseActivity를 만들어 코드를 추가해주면 좋을 것 같다.

WindowManager.LayoutParams _ 관련 속성

FLAG_LAYOUT_IN_SCREEN
연결된 창에 대한 창 플래그: 상위 창의 제약 조건을 무시하고 전체 화면 내에 창을 배치합니다.

FLAG_LAYOUT_NO_LIMITS
창 플래그: 창이 화면 외부로 확장되도록 허용합니다.

추가 _ 코드

: 위의 코드를 추가하여 상태바를 완전히 투명하게 만드는데 성공하였다면, 아마 레이아웃이 상태바의 크기만큼 위로 올라갔다는 사실로 알 수 있을 것이다.
상태바를 투명하게 만들되, 레이아웃 위치를 그대로 유지하고 싶다면, 레이아웃에 상태바의 높이만큼 패딩같은 것을 줘야한다. (네비게이션 바도 마찬가지)

이 또한 activity/fragment 단에서 주면 된다.

// 적용
binding.clMainLayout.setPadding(0,getStatusBarHeight(requireContext()), 0, 0)


// extention.kt
fun getStatusBarHeight(context: Context): Int {
    val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")

    return if (resourceId > 0) {
        context.resources.getDimensionPixelSize(resourceId)
    } else {
        0
    }
}

fun getNaviBarHeight(context: Context): Int {
    val resourceId: Int = context.resources.getIdentifier("navigation_bar_height", "dimen", "android")
    return if (resourceId > 0) {
        context.resources.getDimensionPixelSize(resourceId)
    } else {
        0
    }
}

결과

좋은 웹페이지 즐겨찾기