[Android] 다크 테마(Dark Theme) 만드는 방법
사용자에게 앱의 색상을 변경할 수 있도록 하는 기능을 제공할 때가 있다. 이 때 테마(theme)를 사용해야한다. 그렇지않으면 모든 엑티비티를 호출하는 클래스안에 사용자가 선택한 색상에 따라 액티비티의 색상값들을 변경해줘야하는 삽질을 하게될 확률이 높다. 나 또 한 처음에는 그렇게했었다. 안드로이드를 처음에 접했을 때 테마라는 것을 대충 흘려 보냈기 때문이었고, 그닥 관심을 주지않았다. 이제 그 테마를 사용해보자
다크 테마 만들기(Dark Theme)
안드로이드 매니페스트 파일을 보면 초기 앱 테마(android:theme=”@style/AppTheme”) 라는 스타일을 적용하고 있다.
<application
android:name=".MyAppication"
android:allowBackup="false"
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
tools:replace="android:allowBackup"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
기본테마(AppTheme)는 그대로 두고 다크 테마를 구현해 보자
res/values 디렉토리에서 마우스 오른쪽 버튼을 클릭하거나 또는 alt + Insert 키를 눌러 attrs.xml 파일을 생성한다. 생성을 하면 아래와 같은 기본 resource 파일을 볼 수 있다.
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
사용하게될 속성 값의 이름을 지정해보자.
<attr name={YourAttributeName} format={AttributeType(color,dimension etc)}/>
attrs.xml 파일에 아래 스니펫을 적용해보자.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="bgColor" format="color"/>
<attr name="textColor" format="color"/>
</resources>
다음으로 styles.xml 파일을 열고 다크테마를 만들어야한다. style.xml파일은 res/values/ 디렉토리에 있다. 다크 테마 스타일을 만든 후 attrs.xml파일에서 내가 지정했던 속성이름을 적용해준다.
<style name="DarkTheme" parent="AppTheme">
<item name="textColor">#ffffff</item>
<item name="bgColor">#000000</item>
</style>
<style name="LightTheme" parent="AppTheme">
<item name="textColor">#000000</item>
<item name="bgColor">#ffffff</item>
</style>
테마생성이 완료되었다. 이제 activiy_main.xml 레이아웃에 적용해보자. 테마의 속성을 사용하지 않을 때는 백그라운드 생상을 지정할 때 “@color/colorAccent“와 같은 방식으로 적용하게된다.
하지만 테마의 속성을 적용할 때는 “?attr/bgColor” 처럼 적용한다.
//테마 적용 전 Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="@color/white"
xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/colorAccent"
android:text="다크테마"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="14dp"
android:layout_gravity="center"
android:textColor="@color/colorPrimaryDark"
android:text="테스트"/>
</LinearLayout>
//테마 적용 후 Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="?attr/bgColor"
xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="?attr/textColor"
android:text="다크테마"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="14dp"
android:layout_gravity="center"
android:textColor="?attr/metaTextColor"
android:text="테스트"/>
</LinearLayout>
모든 준비는 끝났다. 이제 마지막으로 MainActivity.java에서 setTheme ()를 사용하여 테마를 설정한다. onCreate ()에서 setContentView ()를 호출하기 전에 setTheme()를 호출하여 적용한다.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//테마 적용
SharedPreferences sharedPreferences= context.getSharedPreferences(PREF_NAME,PRIVATE_MODE);
if(sharedPreferences.isChangeTheme()){
setTheme(R.style.DarkTheme);
}else{
setTheme(R.style.LightTheme);
}
setContentView(R.layout.activity_main);
}
모든 처리가완료되었다. SharedPreferences를 사용하여 사용자가 선택한 값에 따라 밝은 테마나 어두은 테마를 적용할 수 있다. 이 방법을 사용하려면 밝은 테마도 역시 만들어줘야한다.
사용자의 선택이 아닌, 다크테마 모드를 사용자에게 자동으로 지원하고 싶다면 휴대폰이 야간모드인지 체크 후 자동 적용하는 방법이 있다. AppCompatDelegate 클래스를 사용하면 된다. AppCompatDelegate는 안드로이드 지원 라이브러리의 클래스로 다크 테마 구현을 처리하는 방법을 제공한다. 3가지의 파라미터가 있다.
AppCompateDelegate.MODE_NIGHT_YES : 야간 모드 사용 가능
AppCompateDelegate.MODE_NIGHT_NO : 야간 모드 비활성화 또는 다른 모드 활성화.
AppCompateDelegate.MODE_NIGHT_AUTO :이 모드에서는 장치의 타이밍을 고려한 다음 모드가 결정.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
}
setContentView(R.layout.activity_main);
}
setTheme()을 사용하여 setContentView () 전에 호출하여 테마를 설정한다.
if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
setTheme(R.style.DarkTheme);
} else {
setTheme(R.style.LightTheme);
}
setContentView(R.layout.activity_main);
MainActivity.java에서 setTheme ()를 사용하여 테마를 설정한다. onCreate ()에서 setContentView ()를 호출하기 전에 setTheme()를 호출하여 적용한다.
[참고]
https://blog.prototypr.io/implementing-dark-theme-in-android-dfe63e62145d