Android : Kolay Yoldan Ayarlar Ekrani-Preferences API
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
iseentries
’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 setOnBindEditTextListener
kullanarak 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.