Android Dark Mode Kullanımı

Merhaba arkadaşlar,
mobilhanem.com üzerinden anlattığımız/yayınladığımız derslere bugün sizlere Android Dark Mode Kullanımını  anlatan bir uygulama yapacağım.

Android 10 ( API Level 29 ) ile  birlikte ortaya çıkan Android Dark Mode nedir, ne işe yarar öncelikle bunları anlatmakla başlayalım; Dark Mode kullanıcılara koyu bir arayüz ortamı sunmaktadır.

Android Dark Mode Avantajları

  • Parlak ışığa duyarlı olan kullanıcılar için görünürlüğü artırır.
  • Geç saatlerde görsel olarak kendini ayarlayabilen bir ortam kullanıcılara sunmuş olur.
  • Güç kullanımını önemli ölçüde azaltabilir (cihazın ekran teknolojisine bağlı olarak)

Android 10 sürümlerinde Dark Mode aktifleştirmek için cihazın Sistem ayarlarından (Settings -> Display -> Theme) kısmından Dark mode aktifleştirebilirsiniz.

Dark mode da tema desteğini sağlayabilmemiz için res->values->styles.xml de bulunan uygulama temasını aşağıdaki şekilde yeni gelen DayNight tema desteğini ile kullanabiliriz.

<style name="AppTheme" parent="Theme.AppCompat.DayNight">

Uygulamamızda tema kullanıcı tarafından değiştirilmek istenebilir. Dark mode için;

Android 9 veya önceki sürümlerde çalışan cihazlarda önerilen tema seçenekleri aşağıdadır :

  • Light
  • Dark
  • Set by Battery Saver

Android 10 ve daha üst sürümlerde çalışan cihazlarda ise önerilen tema seçenekleri:

  • Light
  • Dark
  • System default

Bu seçeneklerin her biri doğrudan AppCompat.DayNight modlarından birine eşlenir peki nedir bu modlar gelin inceleyelim:

  • Light : MODE_NIGHT_NO: Zamana bağlı kalmadan light mod kullanılmasını sağlar.
  • Dark : MODE_NIGHT_YES: Zamana bağlı kalmadan dark mod kullanılmasını sağlar.
  • Set by Battery Saver: MODE_NIGHT_AUTO_BATTERY: Sistemin pil tasarrufu etkinken, dark mod kullanılmasını sağlar aksi taktirde light mod kullanılır. Bu mod ile birlikte cihazın güç kullanılımın azalmasına yardımcı olunur.
  • System default: MODE_NIGHT_FOLLOW_SYSTEM: Gece olup olmadığını belirlemek için sistemin gece modu ayarını kullanan mod.

Temayı değiştirmek için aşağıdaki kod bloğu kullanılır.

AppCompatDelegate.setDefaultNightMode()

örnek olarak; dark mode yapısını etkinleştirmek için aşağıdaki gibi methoda neyi set etmesini gerektiğini söylüyoruz.

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)

Geçerli dark mode türünü alabilmek için aşağıdaki kod bloğunu kullanırız. Bu method bize integer bir değer döndürür.

AppCompatDelegate.getDefaultNightMode()

Dönen değerler aşağıdaki tiplere karşılık gelmektedir.

MODE_NIGHT_AUTO = 0

MODE_NIGHT_NO = 1

MODE_NIGHT_YES = 2

MODE_NIGHT_FOLLOW_SYSTEM = -1

MODE_NIGHT_UNSPECIFIED = -100

Android Dark Mode Klasör Yapısı

Dark mode yapısını uygulamaya yerleştirmek istediğimizde öncelikle dark mode yapısına göre klasörleme mantığını oturtmamız gerekmektedir. Örnek verecek olursak; uygulamamızda renk kodlarını tutabilmek için kullandığımız colors.xml klasörü normalde bir tane bulunmaktadır ama dark mode göre farklı renkler kullanmak istersek bir tane daha colors.xml oluşturmalıyız.

Android Studio da colors.xml klasör yapısı aşağıdaki gibi olacaktır. colors.xml ve colors.xml (night )

Bu şekilde yapı oluşturabilmek için Android Studio da görünüm olarak sol üst kısımda yer alan Project seçeneğini seçelim daha sonra res klasörüne sağ tıklayıp New -> Android Resource Directory tıkladıktan sonra Directory name kısmına values-night yazarak oluşturalım. Dark mode temasına uygun olarak artık klasöre sahibiz. Artık bu klasör altına dark mode yapısına göre oluşmasını istediğimiz dosyaları yaratabiliriz. ( colors.xml, styles.xml gibi )

örnek klasör yapısı:

Şimdi projemizi oluşturmaya başlayalım;

Öncelikle Dark Mode yapısını Application sınıfı üzerinden yönlendirmek istiyorum bu yüzden Application sınıfı ile ilgili işlemler yapmam gerecek. Aşağıdaki gibi InitApplication adını verdiğimiz bir sınıf oluşturuyoruz.

InitApplication.kt

package com.mobilhanem.darkmodeapp

import android.app.Application
import android.preference.PreferenceManager

class InitApplication : Application() {

    val DARK_MODE = "DARK_MODE"
    var isDarkModeEnabled = false

    companion object {
        private var INSTANCE: InitApplication? = null

        val instance: InitApplication
            get() {
                if (INSTANCE == null) {
                    INSTANCE = InitApplication()
                }

                return INSTANCE!!
            }
    }

    override fun onCreate() {
        super.onCreate()
        INSTANCE = this
        val mPrefs = PreferenceManager.getDefaultSharedPreferences(this)
        this.isDarkModeEnabled = mPrefs.getBoolean(DARK_MODE, false)
    }

    fun setIsDarkModeEnabled(isDarkModeEnabled: Boolean) {
        this.isDarkModeEnabled = isDarkModeEnabled
        val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
        val sharedEditor = sharedPref.edit()
        sharedEditor.putBoolean(DARK_MODE, isDarkModeEnabled)
        sharedEditor.apply()
    }

}

Bu application sınıfını incelersek eğer; singleton bir sınıf yapısı kurduğumuzu göreceksiniz. Application sınıfı yaratıldığında shared preferences yapısından gelen değeri ilgili değişkene set ederiz. Bu değer true veya false olabilir.  setIsDarkModeEnabled methodu da boolean bir değişken alır daha sonra o aldığı değişkeni ilgili değere set eder. Son olarak da Shared Preferences ile de cihaza o değeri kaydetmiş oluruz. Kaydedilen bu değeri kontrol ederek çeşitli işlemler yapacacağız.

Application sınıfını oluşturduktan sonra uygulamamızın ve bu sınıfın sorunsuz çalışabilmesi için AndroidManifest e aşağıdaki gibi android:name kullanarak sınıfımızı tanımlamamız gerekmektedir.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.mobilhanem.darkmodeapp">

    <application
            android:name=".InitApplication"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            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>
    </application>

</manifest>

Şimdi uygulamamızda kullanacağımız renk kodlarını oluşturalım aynı yukarıda anlattığım şekilde hem normal kullanılacak olan renk kodu dosyası hem de dark mode için kullanılacak olan renk dosyasına ihtiyacımız var.

night/colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="red">#ff5311</color>
    <color name="redDark">#ff2c11</color>
    <color name="darkmode_textColor">#D4AC0D</color>
    <color name="switchColor">#BC2F1D</color>
</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="red">#ff8200</color>
    <color name="redDark">#f77000</color>
    <color name="darkmode_textColor">#D4AC0D</color>
    <color name="switchColor">#911DEE</color>
</resources>

Şimdi uygulamamızda kullanacağımız style dosyalarını oluşturalım aynı renk kodlarını oluştururken kullandığımız mantık burası içinde geçerli;

night/styles.xml

<resources>

    <style name="AppTheme" parent="Theme.AppCompat.DayNight">
        <item name="colorPrimary">@color/red</item>
        <item name="colorPrimaryDark">@color/redDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:textColorPrimary">@android:color/white</item>
    </style>

    <style name="CustomDialog" parent="Theme.AppCompat.DayNight.Dialog.Alert"/>

    <style name="CustomSwitch">
        <item name="colorControlActivated">@color/switchColor</item>
    </style>

</resources>

styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="CustomDialog" parent="Theme.AppCompat.Light.Dialog.Alert"/>

</resources>

Şimdi uygulamamızda kullanacağımız resim dosyalarını oluşturalım aynı işlemler resim dosyaları içinde geçerli eğer dark mode için ayrı bir gösterim yapmak istiyorsak o resim dosyasınıda oluşturmamız gerekmektedir. Kaynak kodu indirip incelediğinizde konuyu daha iyi anlayacaksınız. Drawable klasörü için yapı aşağıdaki gibidir. mobilhanem_logo adını verdiğimiz resmi hem normal mod için hem dark mod için kullandığımızı görüyoruz. Bu resimlerin adı aynı olmak zorunda fakat içerikleri farklı olabilir.

Şimdi xml layout dosyasının görsel kısımlarını oluşturalım;

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">


    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_margin="@android:dimen/app_icon_size"
            android:text="Dark mode dersine hoşgeldiniz."
            android:textColor="@color/darkmode_textColor"
            android:textSize="18sp" />

    <ImageView
            android:id="@+id/imageView"
            android:layout_width="250dp"
            android:layout_height="250dp"
            android:layout_centerInParent="true"
            android:src="@drawable/mobilhanem_logo" />


    <TextView
            android:id="@+id/txtNightMode"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBaseline="@+id/switchCompat"
            android:layout_centerHorizontal="true"
            android:paddingRight="8dp"
            android:text="Gece Modu"
            android:textColor="@color/darkmode_textColor" />


    <android.support.v7.widget.SwitchCompat
            android:id="@+id/switchCompat"
            android:layout_width="wrap_content"
            android:theme="@style/CustomSwitch"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="@android:dimen/app_icon_size"
            android:layout_toRightOf="@+id/txtNightMode"
            android:checked="false"
            android:textAppearance="?android:attr/textAppearanceMedium" />

    <Button
            android:id="@+id/clickButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/imageView"
            android:layout_alignLeft="@+id/txtNightMode"
            android:layout_alignStart="@+id/txtNightMode"
            android:text="Tıkla"
            android:textColor="@color/darkmode_textColor" />


</RelativeLayout>

Bu layout a bağlı olan activity sınıfımızıda oluşturalım;

MainActivity.kt

package com.mobilhanem.darkmodeapp

import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.support.v7.app.AppCompatDelegate
import android.support.v7.widget.SwitchCompat
import android.widget.Button

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (InitApplication.instance.isDarkModeEnabled) {
            ThemeHelper.applyTheme(ThemeHelper.DARK_MODE)
        } else {
            ThemeHelper.applyTheme(ThemeHelper.LIGHT_MODE)
        }

        setContentView(R.layout.activity_main)

        val switchCompat = findViewById<SwitchCompat>(R.id.switchCompat)
        val button = findViewById<Button>(R.id.clickButton)
        button.setOnClickListener {
            AlertDialog.Builder(this, R.style.CustomDialog)
                .setTitle("Başlık")
                .setMessage("Mesaj")
                .show()
        }

        if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES)
            switchCompat.isChecked = true

        switchCompat.setOnCheckedChangeListener { buttonView, isChecked ->
            if (isChecked) {
                InitApplication.instance.setIsDarkModeEnabled(true)
                recreate()

            } else {
                InitApplication.instance.setIsDarkModeEnabled(false)
                recreate()
            }
        }


    }
}

ThemeHelper adını verdiğimiz uygulama içinde hangi temanın kullanılacağına karar veren mekanizmayıda aşağıdaki gibi oluşturuyoruz.

ThemeHelper.kt

package com.mobilhanem.darkmodeapp

import android.support.v7.app.AppCompatDelegate

object ThemeHelper {

    const val LIGHT_MODE = "light"
    const val DARK_MODE = "dark"

    fun applyTheme(theme: String) {

        val mode = when (theme) {

            LIGHT_MODE -> AppCompatDelegate.MODE_NIGHT_NO
            DARK_MODE -> AppCompatDelegate.MODE_NIGHT_YES

            else -> {
                AppCompatDelegate.MODE_NIGHT_NO
            }
        }

        AppCompatDelegate.setDefaultNightMode(mode)
    }
}

Yukarıdaki kod bloklarını incelersek; Application sınıfı üzerinden oluşturduğumuz değişken değerinin kontrol edildiğini göreceksiniz eğer o değer kayıtlı ise yani değişken true ise ThemeHelper üzerinden dark mode aktifleştirdiğimizi görüyoruz eğer değer kayıtlı değil ise yani değişken false ise ThemeHelper üzerinden light mode aktifleştirdiğimizi görüyoruz. SwitchCompat seçili ise Application sınıfı üzerinden ilgili methodu true göndererek çağırdığımızı görüyoruz. Eğer seçili değilse ilgili methoda false gönderiyoruz. Bu işlemlerden sonra tema değişeceği için ilgili sayfayı yenilememiz gerekmektedir işte bu yüzden recreate methodunu çağırıyoruz.

Uygulamamızı çalıştırdığımızda light mode için aşağıdaki ekran görüntüsünü elde edeceğiz.

Uygulamamızı çalıştırdığımızda dark mode için aşağıdaki ekran görüntüsünü elde edeceğiz.

Evet arkadaşlar Android Dark Mode Kullanımını temel bir proje yaparak sizlere anlatmaya çalıştım. Umarım herkese faydalı olmuştur kaynak kodu indirip çalıştırdığınızda konuyu daha iyi anlayacaksınızdır. İlerleyen derslerde Android 10 ile gelen yeni özelliklere değinmeye çalışacağım.

Tüm Android Ders, Proje ve Kaynak Kodlar için tıklayınız.

Mobilhanem.com üzerinden anlattığımız android uygulama geliştirme derslerine devam edeceğiz. Konu hakkında sorunuzu yorum alanından sorabilirsiniz. Konu dışı sorularınızı ve tüm yazılımsal sorularınızı sorucevap.mobilhanem.com sitemizden de sorabilirsiniz.

Bir dahaki dersimizde görüşmek dileğiyle..

3

Alper Beyler

Yüksek Lisans: Çankaya Üniversitesi / Bilgisayar Mühendisliği
Lisans: Çankaya Üniversitesi / Bilgisayar Mühendisliği (4/3.30) (2010-2014)
Lisans : Viyana Teknik Üniversitesi / Bilgisayar Bilimleri (2013)

3 Yorum

Haftalık Bülten

Mobilhanem'de yayınlanan dersleri haftalık mail almak ister misiniz?