Android : Kolay Yoldan Ayarlar Ekrani-Preferences API

Süleyman Sezer
HardwareAndro
Published in
7 min readOct 13, 2020

Uygulamamız için ayarlar ekranı oluşturmak her zaman uğraştırıcı bir işlemdir. Bunun çözümü için Jetpack içerisinde Preferences API geliştirildi.Bu sayede kolay yoldan ayarlar ekranı yapabiliriz.

Projemizde Preferences API’yi kullanabilmek için build.gradle içerisine şu kütüphaneyi eklememiz gerekiyor:

androidx.preference:preference:1.1.0

Artık projemizde Fragment — > Settings Fragment yolunu izleyerek hızlıca ayarlar ekranı oluşturabiliriz.

Preference API aslında bir fragmenttir ve PreferenceFragmentCompat’tan miras almaktadır.

class SettingsFragment : PreferenceFragmentCompat() {

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}

İlk oluşturduğumuzda şöyle bir kod bloğu gelmektedir. Normal activitylerde onCreate durumu varken burada onCreatePreferences fonksiyonu bulunmaktadır. Burada XML’i bind ediyoruz ve içerisinde tasarımımızı yapıyoruz.

Bundan sonrasında örnek üzerinden gitmek istiyorum. Çünkü anlaşılması daha kolay olur düşüncesindeyim.

Örneğin şöyle bir ekranımız olsun. Burada kullanıcı mailini değiştirebildiği bir edittext, cinsiyetini seçilebildiği bir liste, yaşını seçebileceği bir seekbar, tema ayarını yapabileceği bir switch button ve siteye yönlendirme yapan bir iteme sahip olsun.

Tasarımımız genel manada şöyle bir tree şeklinde olacaktır.

Burada PreferenceScreen bütün itemleri içinde barıntıran parent bir layouttur. Layout dedik ama burada herhangi bir layout kullanamıyoruz.(Linear,constraint,relative,frame vs) Eklediğimiz itemlerse linear layoutta olduğu gibi alt alta eklenmektedir.

Kodları res → xml → root.xml içerisinde yazıyoruz.

Önce kategori oluşturmamız gerekiyor. Bunun için PreferenceCategory oluşturuyoruz.

<PreferenceCategory
app:icon="@drawable/ic_baseline_person_24"
app:title="@string/profile_info">
</PreferenceCategory>

Artık arayüzde bir kategorizasyon yapabiliriz. Burada icon ile başlığın soluna bir adet ikon, title ile de başlığı yazdırıyoruz. Sonuç olarak şöyle bir ekran elde ediyoruz.

Kategori oluşturduğumuza göre şimdi kullanıcının mail adresini girebileceği bir edittext oluşturmamız gerekiyor. Bunun için de Preferences API’nin bize sunduğu EditTextPreference itemini kullanıyoruz.

<EditTextPreference
app:key="mail"
app:defaultValue="example@hello.com"
app:title="Mail Adress"
app:useSimpleSummaryProvider="true" />

Burada key kısmıyla bu EditTextPreferences’e kod kısmından ulaşabiliriz. defaulValue seçeneği, edittext alanı açıldığında bize örnek olarak gösterilen metindir. title kısmında, bu itemin başlığında ne gözükeceğini yazarız. useSimpleSummaryProvide ise açılan ekranda eğer kullanıcı bir metin girdiyse veya bir bölümünü değiştirdiyse bunu bir önceki sayfada kullanıcıya göstermesi için true değeri alıyor.

Ayrıca bu key ile girdiğiniz veri SharedPreferences’a kaydedilmektedir. Bunu biraz aşağıda anlatacağım.

Yukarıdaki resimde de görüldüğü üzere Mail Adress’e basınca dialog açılıyor ve içerisinde veriyi değiştirebiliyoruz. useSimpleSummaryProvider değerine true verdiğimiz için değiştirilen emaili kullanıcı son ekranda görebiliyor.

Şimdiyse cinsiyet seçimi için liste oluşturmaya geçelim. Bunun için ListPreference ismindeki itemi kullanıyoruz ve kullanımı şu şekilde oluyor:

<ListPreference
app:key="gender"
app:defaultValue="Not Selected Gender"
app:entries="@array/gender_entries"
app:entryValues="@array/gender_values"
app:title="Select your gender"
app:useSimpleSummaryProvider="true" />

Burada key kullanımı yukarıdaki EditTextPreference ile aynıdır. O key ismiyle hem veriler SharedPreferences’a kaydedilmekte hem de kodda bu iteme erişmek için kullanılmaktadır. defaultValue de uygulama ilk açıldığında veya kullanıcı hiçbir ayar yapmadığı zaman geçerli olan değerdir.

Burada önemli olan 2 kavram var. Bunlar entries ve entryValues’dir. Bu iki değer parametre olarak dizi beklemektedir.

entries, aldığı listeyi kullanıcıya gösterir. entryValues ise entries’de seçilen dizinin indeksine göre kendi dizisindeki veriyi SharedPreferences’a kaydeder.

Örneğin ben burada entries’e yani kullanıcıya gösterilmesi gereken listeyi şu şekilde oluşturdum:

<string-array name="gender_entries">
<item>Male</item>
<item>Female</item>
</string-array>

Ve entryValues’e yani SharedPreferences’a kaydedilecek değerler listesini de şu şekilde oluşturdum:

<string-array name="gender_values">
<item>0</item>
<item>1</item>
</string-array>

Artık kullanıcı listeden Male seçeneğini seçince SharedPreferences’a 0 değeri kaydedilmektedir.

Artık şöyle bir cinsiyet seçim ekranımızı elde etmiş oluyoruz. Üstte yazdığım gibi entries’in aldığı liste burada kullanıcıya gösterilmektedir.

Şimdiyse kullanıcının yaşını seçebileceği bir seekBar oluşturmaya geldi.

<SeekBarPreference
app:key="age"
app:title="Age"
android:max="100"
app:min="0"
app:defaultValue="23"
app:showSeekBarValue="true" />

Burada max değeriyle barın alacağı en yüksek değeri, min değeriyle de en düşük değerini yazıyoruz. Yine defaultValue ile de barın uygulama ilk açıldığında alacağı değeri giriyoruz. showSeekBarValue ise; eğer barın değeri değişiyorsa kullanıcının bunu görmesi için sağ tarafta bir metin alanı oluşturur ve yeni değeri burada gösterir. Eğer göstermesini istiyorsak true değerini veririz. Yine key ile barın o anki değeri SharedPref’e kaydedilmektedir.

Artık bir seekBarımız var ve sağ tarafında da yeni değerini görebiliyoruz.

Şimdi de kullanıcının ülke seçmesi için bir DropDownPreference oluşturmaya geldi.

<DropDownPreference
android:key="country"
android:title="Your Country"
android:defaultValue="Turkey"
android:entries="@array/country_entries"
android:entryValues="@array/country_values"
app:useSimpleSummaryProvider="true" />

Bunun kullanımıyla ListPreference kullanımı arasında bir fark yoktur. Sadece tek fark ListPreference kullandığımızda kullanıcı seçimi için ekranda bir dialog açılırken DropDownPreference ile kullanıcıya açılır kapanır bir liste gösterilmektedir.

Artık ilk kategorimiz tamamlandı. Şimdiyse sıra SwitchButonlar kullanılarak oluşturulmuş 2.kategoriyi oluşturmada.

Bunun için yine PreferenceCategory kullanarak bir kategori oluşturuyoruz ve şu şekilde Switch ekliyoruz:

<SwitchPreferenceCompat
app:key="appThemeDark"
app:title="Dark Theme"
android:defaultValue="false" />
<SwitchPreferenceCompat
app:key="appThemeLight"
app:title="Light Theme"
android:defaultValue="true" />

2 Switch butonuda aynı olduğu için tek kodda ekledim. Burada önemli olan kısım defaultValue kısmı. Eğer true değerini alırsa SwitchButton aktif, false değerini alırsa pasif durumuna geçiyor.

Şimdiyse hemen diğer switch butonuna geçelim. Çünkü olaylar orada 😄

<SwitchPreferenceCompat
app:key="colorBlindMode"
app:title="Color Blind Mode"
app:dependency="appThemeLight"
app:summaryOff="Color blind mode passive"
app:summaryOn="Color blind mode active" />

Burada hemen gözümüze dependency kısmı çarpıyor. Bu kısım bu itemin herhangi bir itemle bağlılığı olup olmadığının verisini almaktadır. Ben burada appThemeLight’a bağımlılık verdim. Yani appThemeLight switch butonu eğer aktif durumduysa bu switch buton aktif hale gelebilir durumda olacaktır. Eğer appThemeLight switch butonu pasif durumdaysa bu switch butonda pasif duruma geçecek ve aktif edilemeyecektir.

summaryOn ve summaryOf parametre olarak aldığı stringleri ekranda göstermektedir. Yani switch butonu aktifse summaryOn’da girilen string değeri gösterilecek, eğer pasif durumdaysa summaryOff’da yazan string değeri gösterilecektir.

Yukarıdaki resimde görüldüğü gibi kullanıcı Light Theme switchini aktif ettiği durumda Color Blind Mode özelliğini de aktif edebilir durumda olacaktır. Ama kullanıcı Dark Theme switchini aktif durumuna getirdiği zamansa Color Blind Mode devre dışı kalacaktır. İşte bu bağlılığı yukarıda da anlattığım üzere dependency‘i kullanarak gerçekleştiriyoruz.

Gelelim ekranımızdaki son itemi oluşturmaya. Kullanıcının sitemizi ziyaret etmesini sağlayan bir buton oluşturmaya yani Preferences oluşturmaya.

<Preference
app:key="webPage"
app:title="Web Page"
app:icon="@drawable/ic_baseline_web_24">
<intent
android:action="android.intent.action.VIEW"
android:data="https://www.patronusstudio.com"/>
</Preference>

Preferences aslında boş bir itemdir. Bu itemin key, title, icon, summary, dependency, defaultValue, singleLineTitle gibi pek çok parametre alan özelliği vardır. Biz burada web sayfasına yönlendirmesi için kullanacağız. Bunu da intent ile gerçekleştireceğiz. Burada action ile intentin ne yapacağı, data ile de alacağı veriyi giriyoruz. Artık preferencesa tıklandığı anda web sayfasına yönlendirme yapacaktır.

Ayrıca bunu XML’de yapmak yerine kod kısmında da yapabiliriz. Yani şu şekilde:

<Preference
app:key="webPage"
app:icon="@drawable/ic_baseline_web_24"
app:title="Web Page"/>

XML’ de şu şekilde preference oluşturuyoruz ve root_preferences içerisinde şunu yazıyoruz:

val webPreference = findPreference<Preference>("webPage")
val webIntent = Intent(Intent.ACTION_VIEW)
webIntent.data = Uri.parse("http://www.patronusstudio.com")
webPreference?.intent = webIntent

Burada findPreference ile oluşturduğumuz Preferenceslara ulaşabiliyoruz. Tabi tipini ve hangi Preferences’a ulaşacağımızı key ile belirtmemiz gerekiyor. Daha sonrasında intent yardımıyla verileri ayarlıyoruz ve Preferences’a bu intenti gönderiyoruz. Artık tıklama işlemiyle web sayfasına yönlendiriliyoruz.

Ayrıca başka bir ayarlar ekranı oluşturup intent kullanarak buradan geçişi de sağlayabiliriz.

Artık Web Page Preferences’ımıza tıkladığımızda yönlendirme yapılıyor. Bunu da intent ile gerçekleştiriyoruz.

Artık uideki tüm özelliklerimizi oluşturduk. Şimdi gelin XML’de kodları biraz Kotlin koduna dökelim ve neler yapabiliyoruz bir bakalım.

Yukarıda app:useSimpleSummaryProvider=”true” diye bir item özelliği kullanmıştık. Bunun yerine SummaryProvider kullanarak verilen değiştiğinde callbackler alabiliriz ve kendi özel fonksiyonlarımızı burada gerçekleştirebiliriz.

val edx = findPreference<EditTextPreference>("mail")
edx?.summaryProvider=EditTextPreference.SimpleSummaryProvider.getInstance()

Örneğin yukarıdaki kodda useSimpleSummaryProvider yerine onun bir Instance’sini alıp EditTextPreference’ye set edebiliriz. Bu sayede değerler otomatik değiştiğinde ekranda önizleme olarak gözükmesini sağlayabiliriz.

Aynı şekilde SummaryProvider’i özelleştirebiliriz de :

val edx = findPreference<EditTextPreference>("mail")
edx?.summaryProvider = Preference.SummaryProvider { preference: EditTextPreference? ->
val text = if (preference != null) preference.text else "Hata"
if (text.isNotEmpty()) "Kaydedilen Değer $text"
else "Değer Girilmedi"
}

Artık mail girildikten sonra kullanıcıya bunu Kaydedilen Değer : şeklinde gösterebiliyoruz. Burada istediğimiz gibi düzenlemeler yapabiliriz.

Örneğin edittext içerisinde sadece sayı girilmesini istersekte:

val edx = findPreference<EditTextPreference>("mail")
edx?.setOnBindEditTextListener { editText->
editText.inputType=InputType.TYPE_CLASS_NUMBER
}

Şu şekilde bir setOnBindEditTextListenerkullanarak girilen değerleri sadece sayı olmasını sağlayabiliriz.

Yukarıdaki ui tasarımını oluşturduk. Peki bu veriler SharedPreferences’a nasıl kaydediliyor bir bakalım.

Bunu görebilmek için :

Device File Explorer → data → data → proje paket ismi → shared_prefs

yolunu izleriz ve dosyamızı shared_prefs klasörünün altında buluruz. Dosya isimlendirmesine gelirsek, örneğin sizin projenizin paket ismi şu olsun :

  • com.medium.blogprojem

Oluşan SharedPreferences dosyasının ismiyse şu şekilde oluşur:

  • com.medium.blogprojem_preferences.xml

şeklinde oluşacaktır. blogprojem_preferences.xml içerisinde girecek olursakta:

Şu şekilde verilen key-value olarak saklandığını görebiliriz. Peki bu verilere nasıl erişebiliriz dersek:

val pref=PreferenceManager.getDefaultSharedPreferences(this.context)
val email=pref.getString("mail","error")

Şu şekilde önce SharedPreferences’a, sonra da onun sakladığı değere erişebiliriz.

Eğer SharedPreferences hakkında daha fazla bilgi edinmek isterseniz bir önceki yazıma şuradan erişebilirsiniz.

Proje kodlarınaysa şuradan erişebilirsiniz.

--

--

Süleyman Sezer
HardwareAndro

Native Android Developer at Anadolu Hayat Emeklilik