Android

[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

Leave a Reply

error: Content is protected !!