(Android) night theme 적용하기
Android 에서 Night 테마를 적용하는 방법을 알아보겠습니다

1. Night resource 분리
Night theme를 적용하기 위해서는 values-night 폴더에 theme/colors 리소스가 추가되어야 합니다
먼저 리소스폴더에 values-night 폴더를 생성하고, values 폴더에 있는 themes.xml 과 colors.xml 을 복사해줍니다
project의 main 폴더에서 values-night 폴더에 각 파일을 추가하면 아래처럼 파일이 위치하게 됩니다
$ find . -name themes.xml
./res/values/themes.xml
./res/values-night/themes.xml
$ find . -name colors.xml
./res/values/colors.xml
./res/values-night/colors.xml
2. resource 내용 수정
2-1. values-night/themes.xml 수정
테마의 parent를 Night 테마로 변경해줍니다.
기존 parent를 보고 적절하게 변경합니다
기존 parent | 변경할 값 |
Theme.MaterialComponents.DayNight | Theme.MaterialComponents.DayNight.DarkActionBar |
Theme.AppCompat.DayNight | Theme.AppCompat.DayNight.DarkActionBar |
만약 windowLightStatusBar 가 설정되어있었다면 false 로 변경합니다
<item name="android:windowLightStatusBar" tools:targetApi="m">false</item>
최종 theme 내용은 아래와 같습니다 (언급하지 않은 다른 값들은 무시해주세요)
<!-- values-night/themes.xml --> | |
<resources xmlns:tools="http://schemas.android.com/tools"> | |
<!-- Base application theme. --> | |
<style name="Theme.Examples" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <!-- 이부분 변경 --> | |
<item name="colorPrimary">@color/color_primary</item> | |
<item name="colorPrimaryVariant">@color/color_primary2</item> | |
<item name="colorOnPrimary">@color/color_text_1</item> | |
<!-- Secondary brand color. --> | |
<item name="colorSecondary">@color/color_inverse</item> | |
<item name="colorSecondaryVariant">@color/color_inverse2</item> | |
<item name="colorOnSecondary">@color/color_text_inverse_1</item> | |
<!-- Status bar color. --> | |
<item name="android:statusBarColor" tools:targetApi="l">@color/color_layout_background</item> | |
<item name="android:windowLightStatusBar" tools:targetApi="m">false</item> <!-- 이부분 변경 --> | |
</style> | |
</resources> |
<!-- values/themes.xml --> | |
<resources xmlns:tools="http://schemas.android.com/tools"> | |
<!-- Base application theme. --> | |
<style name="Theme.Examples" parent="Theme.MaterialComponents.DayNight"> | |
<item name="colorPrimary">@color/color_primary</item> | |
<item name="colorPrimaryVariant">@color/color_primary2</item> | |
<item name="colorOnPrimary">@color/color_text_1</item> | |
<!-- Secondary brand color. --> | |
<item name="colorSecondary">@color/color_inverse</item> | |
<item name="colorSecondaryVariant">@color/color_inverse2</item> | |
<item name="colorOnSecondary">@color/color_text_inverse_1</item> | |
<!-- Status bar color. --> | |
<item name="android:statusBarColor" tools:targetApi="l">@color/color_layout_background</item> | |
<item name="android:windowLightStatusBar" tools:targetApi="m">true</item> | |
</style> | |
</resources> |
2-2. values-night/colors.xml 수정
취향에 맞게 각 값을 설정합니다
Night theme가 적용되었을 때 적절하게 어두운 배경에 어두운 텍스트를 보여줄 수 있도록 각 값을 변경합니다
이 예제에서는 몇가지 공통적으로 사용할 값을 설정하였습니다
<!-- values-night/colors.xml --> | |
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<color name="color_primary">#18181A</color> | |
<color name="color_primary2">#24242F</color> | |
<color name="color_primary3">#44444F</color> | |
<color name="color_accent">#0CFF6F</color> | |
<color name="color_layout_background">@color/color_primary</color> | |
<color name="color_item_background">@color/color_primary2</color> | |
<color name="color_item_selected">#D4D4D4</color> | |
<color name="color_text_1">#E1E1E1</color> | |
<color name="color_text_2">#C1C1C1</color> | |
<color name="color_text_3">#A1A1A1</color> | |
<color name="color_text_4">#818181</color> | |
</resources> |
<!-- values/colors.xml --> | |
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<color name="color_primary">#EAEAEA</color> | |
<color name="color_primary2">#FFFFFF</color> | |
<color name="color_primary3">#DDDDDD</color> | |
<color name="color_layout_background">@color/color_primary</color> | |
<color name="color_item_background">@color/color_primary2</color> | |
<color name="color_item_selected">#4D4D4D</color> | |
<color name="color_text_1">#313131</color> | |
<color name="color_text_2">#5A5A5A</color> | |
<color name="color_text_3">#8d9298</color> | |
<color name="color_text_4">#A0A0A0</color> | |
</resources> |
3. layout/drawable 수정
layout, drawable에 작성한 내용 중 테마를 적용할 곳들의 color를 colors resource를 사용하도록 변경해야합니다 (익숙해지다보면 프로젝트 초기부터 color resource에 정의해서 사용하는 습관을 가지게 됩니다)
예를 들어 아래의 background_item.xml 의 배경색은 @color/color_item_background로 설정하였기 때문에 Light theme에서는 #24242F로, Night theme에서는 #FFFFFF로 보여지기를 기대할 수 있습니다
<?xml version="1.0" encoding="utf-8"?> | |
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/color_item_selected"> | |
<item> | |
<shape android:shape="rectangle"> | |
<solid android:color="@color/color_item_background" /> | |
<corners android:radius="@dimen/radius_large" /> | |
</shape> | |
</item> | |
</ripple> |
4. theme 적용
AppCompatDelegate.setDefaultNightMode method로 테마를 적용할 수 있습니다
아래 예제에서는 버튼이 눌렸을 때 각각 테마를 설정하도록 하였습니다
각각의 값이 직관적이기때문에 별도의 설명은 생략합니다
class FragmentThemeViewModel { | |
fun onThemeDefault(view: View) { | |
setTheme(AppCompatDelegate.MODE_NIGHT_NO) | |
} | |
fun onThemeNight(view: View) { | |
setTheme(AppCompatDelegate.MODE_NIGHT_YES) | |
} | |
fun onThemeSystem(view: View) { | |
setTheme(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) | |
} | |
private fun setTheme(mode: Int) { | |
AppCompatDelegate.setDefaultNightMode(mode) | |
} | |
} |