Android - Darkmode 활성화하는 방법

JS · 15 Nov 2020

다크모드를 지원하도록 앱을 개발했습니다. 그런데 언제 다크모드로 변경될까요?

앱에서 아무 설정을 하지 않았다면 시스템 설정에 따라서 다크모드로 변경됩니다. 만약 사용자가 Settings에서 Dark mode를 활성화하지 않았다면 앱은 항상 Light mode로 동작하게 됩니다.

물론, 사용자가 Settings의 설정을 변경하지 않더라도 앱에서 다크모드를 활성화시키는 메뉴를 제공할 수도 있습니다.

이 글에서는 다음 내용들에 대해서 알아보겠습니다.

  • App에서 다크모드를 활성화하는 방법
  • Settings에서 다크모드를 활성화하는 방법

Settings에서 다크모드를 활성화하는 방법

DarkMode는 [Settings -> Display -> DarkTheme]에서 설정할 수 있습니다. settings - darkmode

또는 StatusBar의 QuickPannel에서 쉽게 활성화, 비활성화 시킬 수 있습니다. statusbar quickpannel darkmode

시스템 설정이 변경될 때마다 내 앱이 Dark mode로 동작하거나 Light mode로 동작합니다.

Schedule 옵션

Settings에서 Dark theme에 들어가면 좀 더 세밀한 설정을 할 수 있습니다. Schedule 버튼을 누르면 다음과 같이 시간에 따라서 자동으로 다크모드가 활성화되고 비활성화되도록 만들 수 있습니다. settings darkmode schedule

  • Turns on at custom time : 다크모드가 설정되는 시간을 직접 정할 수 있습니다.
  • Turns on from sunset to sunrise : 일출, 일몰 시간에 다크모드가 변경됩니다. 일출, 일몰 시간은 TwilightService에서 가져옵니다.

App에서 다크모드를 활성화하는 방법

Settings에서 다크모드를 활성화했다면 모든 앱이 다크모드로 동작합니다.

디바이스는 Light mode로 설정되어있을 때, AppCompatDelegate API를 사용하면 내 앱만 다크모드로 동작하게 만들 수 있습니다.

AppCompatDelegate API는 다음 3가지 옵션을 제공합니다.

  • Dark mode로 동작
  • Light mode로 동작
  • System 설정으로 동작

Dark mode로 동작

아래 코드 호출 시, 앱은 재실행되며(Activity.onCreate가 다시 호출됨) Dark mode로 동작합니다.

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)

Light mode로 동작

아래 코드 호출 시, 앱은 재실행되며(Activity.onCreate가 다시 호출됨) Light mode로 동작합니다.

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)

System 설정으로 동작

아래 코드 호출 시, System 설정으로 앱이 동작합니다.

Android10(Q OS) 부터 DarkMode가 지원되었기 때문에 Android10 이상은 MODE_NIGHT_FOLLOW_SYSTEM을 설정하고, Android10 미만은 MODE_NIGHT_AUTO_BATTERY를 설정해야 합니다.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    AppCompatDelegate.setDefaultNightMode(
        AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
} else {
    AppCompatDelegate.setDefaultNightMode(
        AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
}

Darkmode 설정 값 확인

getDefaultNightMode()는 앱에서 setDefaultNightMode()으로 설정한 모드를 리턴합니다.

이것을 이용하여 다음과 같이 구현하면 다크모드가 Toggle되도록 만들 수 있습니다.

if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_NO) {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
} else {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}

DarkMode 변경 시, 앱 재실행되지 않도록 만들기

DarkMode 설정이 변경되면 System은 앱을 재실행시킵니다. onCreate()가 다시 호출되게 되며 모든 초기화를 다시 하게 됩니다.

만약 초기화할 것이 많아 앱 실행이 오래 걸리는 등의 문제가 있다면 Manifest에 configChanges="uiMode"를 설정하여 재실행되지 않도록 만들 수 있습니다.

<activity android:name=".MainActivity"
    android:configChanges="uiMode">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

위처럼 설정하면 Dark mode가 활성화되었을 때 앱은 재실행되지 않고, Activity.onConfigurationChanged()으로 Configuration이 변경되었다는 이벤트가 전달됩니다.

다음과 같이 UI_MODE_NIGHT_MASK으로 uiMode를 마스킹하여 Light mode인지 Dark mode인지 구분할 수 있습니다.

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)

    val nightMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
    when (nightMode) {
        Configuration.UI_MODE_NIGHT_NO -> {
            Log.d("Test", "onConfigurationChanged. UI_MODE_NIGHT_NO")
        }
        Configuration.UI_MODE_NIGHT_YES -> {
            Log.d("Test", "onConfigurationChanged. UI_MODE_NIGHT_YES")
        }
    }
}

이 상태에서 앱의 UI는 변경되지 않은 상태입니다. onConfigurationChanged()으로 이벤트를 받고 다음과 같은 처리를 해줘야 합니다.

  • 아무것도 하지 않는다면 UI는 DarkMode의 리소스로 변경되지 않음
  • 필요한 부분만 DarkMode의 리소스로 변경
  • 현재 하는 작업을 모두 마치고(Ex. 동영상 시청) 그 뒤에 Activity가 재실행되게 만듬

시스템에 의해서 DarkMode 설정이 변경되거나 또는 AppCompatDelegate으로 내 앱의 설정을 변경할 때 모두 onConfigurationChanged()이 호출됩니다.

댓글을 보거나 쓰려면 이 버튼을 눌러주세요.
codechachaCopyright ©2019 codechacha