How to implement Android Jetpack Preferences - Android UIX

Implementing a Settings screen in your application is the best way to provide a better user experience by giving users various options to use the application according to the way they want. 

For ex, your application can let the user select the tone for the notification received from the application. 

There are two ways of using the preferences in our application. 

They are:

The XML way: Here, you declare all your preferences in an XML file and use this file in your activity.

The coding way: Apart from XML, you can also write codes for the Preferences in your activity. 

I recommended to use xml way to avoid writing so many lines of code.

We need to add the below line in your app-level build.gradle file to use the Preferences Library

 implementation "androidx.preference:preference-ktx:1.2.0"

..

res / xml / settings_preference.xml:

In order to add the Preferences in your app, you have to add an XML directory. In this directory, you can write the XML code for your preferences. So, in the res directory create an XML directory.


The basic structure of the Preference XML file will be

<PreferenceScreen>
    <Preference>
        <!-- preference1 -->
    </Preference>
    <Preference>
        <!-- preference2 -->
    </Preference>
</PreferenceScreen>

  • Preference Screen by adding the PreferenceScreen tag in your XML file. 
  • Inside this tag, you can add your preferences using the Preference tag.
  • The PreferenceCategory tag to put your preferences in a category. For example, you can group together the UI Preferences in one group and the sounds Preferences in the other category.

Basic Preferences
You can perform a number of tasks using the Settings option of your application, but the easiest and the most common ones are 
  • Simple Text, 
  • Simple Text with some summary, 
  • Simple Text with icon and 
  • Simple Text with some styles or text decoration.
<Preference
    app:key="preference_example"
    app:title="@string/title_preference"
    app:summary="@string/summary_preference"/>

  • app:key is used to uniquely identify a preference. By doing so, you can easily retrieve the value of a particular Preference. 
  • app:title is used to add the title of the Preference
  • app:summary is used to provide some summary to the preferences. This is generally used to describe what the preference is all about. 

res/values/strings.xml

To style your simple text Preference you can add styles in your string and use the same string in your XML. 

For example, add the below string in your res/values/strings.xml

    <string name="title_preference_simple">Simple text title</string>
    <string name="title_preference"><b>You</b> <i>are</i> <u>awesome</u></string>
    <string name="summary_preference">You can use some styles in your preferences by using the described way.</string>

..

To add some icons to your Preferences by using the app:icon attribute.

<Preference
    app:key="icon_example"
    app:title="@string/title_preference"
    app:summary="@string/summary_preference"
    app:icon="@drawable/ic_android"/>

..

If the texts used in your Preferences are not fitting in one line due to screen size or larger font size or any other reason, you can use the app:singleLineTitle attribute to display only that amount of text that is fitted in the screen.

<Preference
    app:key="single_line_title"
    app:title="@string/title_single_line_title_preference"
    app:summary="@string/summary_single_line_title_preference"
    app:singleLineTitle="true"/>

So, the following is the output of all the above Basic Preferences:

..

In order to use Preferences by writing codes, you can use the below code:

val simplePreference = Preference(context).apply {
    key = "simple_preference" //to set the KEY
    title = "Titie of Preference" //to set the TITLE
    summary = "Summary of Preference" //to set the SUMMARY
    icon = ContextCompat.getDrawable(context, R.drawable.ic_android) //to add ICON
    isSingleLineTitle = true //to set one line title
}

..

Dialogs

You can use Dialogs in your Preferences. 

That dialog can be of any type i.e. you can use some Alert dialog or an EditText dialog or some dialog having single or multi-select list Preference.

In order to use an EditText Preference, just use the EditTextPrefernce tag and the best part of it is, by using the app:useSimpleSummaryProvider attribute, you can set your summary to the text entered in the EditText.

 <EditTextPreference
        app:key="edittext_example"
        app:title="@string/title_preference"
        app:useSimpleSummaryProvider="true"
        app:dialogTitle="@string/dialog_title_preference"/>

If you don’t want to use the XML file, then you can use the EditText preference by using the below code:

val editTextPreference = EditTextPreference(context).apply {
    key = "edittext_example"
    ...
}

..

To use a ListPrefernce, use the ListPrefernce tag and put your entries in the list by using the app:entries tag.

 Also, you define the values that are associated with each entry of the list by using the app:entryValues. So, add the below entries and values in your res/arrays.xml file:

<string-array name="entries">
    <item>First Value</item>
    <item>Second Value</item>
    <item>Third Value</item>
</string-array>

<string-array name="entry_values">
    <item>1</item>
    <item>2</item>
    <item>3</item>
</string-array>

After adding entries, use the ListPreference tag to add the List Preference:

 <ListPreference
            android:entryValues="@array/list_preference_entry_values"
            app:entries="@array/list_preference_entries"
            app:key="key_preference_list"
            app:title="List Preference"
            app:useSimpleSummaryProvider="true" />

To use a ListPreference programmatically, you can use the below code:

val listPreference = ListPreference(context).apply {
    key = "list_example"
    title = "@string/title_preference"
    entries = arrayOf("First Value", "Second Value", "Third Value")
    entryValues = arrayOf("1", "2", "3")
}

..

To use the Multi-Select ListPreference, you can use the MultiSelectListPreference tag like below:

 <MultiSelectListPreference
            android:entryValues="@array/list_preference_entry_values"
            app:entries="@array/list_preference_entries"
            app:key="key_preference_multi_select_list"
            app:title="Multi Select List Preference" />

To use the MultiSelectListPreference programmatically, you can use the below code:
val multiSelectListPreference = MultiSelectListPreference(context).apply {
    key = "multi_select_list"
    title = "@string/title_preference"
    summary = "@string/summary_preference"
    entries = arrayOf("First Value", "Second Value", "Third Value")
    entryValues = arrayOf("1", "2", "3")
}

..

Widgets

You can use various widgets such as 
  • Checkbox, 
  • Switch, 
  • Dropdown, and 
  • Seekbar in our Preference.


To use a Checkbox in your Preference, you can use the CheckBoxPreference in your XML file:
 <CheckBoxPreference
            app:key="key_preference_check_box"
            app:title="Checkbox Preference" />
To implement programmatically, you can use:
val checkBoxPreference = CheckBoxPreference(context).apply {
    key = "checkbox_example"
    ...//other attributes
}
..
To use the Switch Preference, you can use the SwitchPreferenceCompat in your XML file:
   <SwitchPreferenceCompat
            app:icon="@drawable/ic_visibility_black_24dp"
            app:key="key_preference_switch"
            app:summary="Tap to show/hide below preference"
            app:title="Switch Preference" />
To implement programmatically, you can use:
val switchPreference = SwitchPreferenceCompat(context).apply {
    key = "checkbox_example"
    ...//other attributes
}
..
You can use the Drop Down Preference in the same way as used for the ListPreference, but here, you have to use the DropDownPreference tag:
 <DropDownPreference
            app:key="dropdown_example"
            app:title="Drop Down Preference"
            app:useSimpleSummaryProvider="true"
            app:entries="@array/list_preference_entries"
            app:entryValues="@array/list_preference_entry_values"/>
To implement Drop Down programmatically, you can use:
val dropDownPreference = DropDownPreference(context).apply {
    key = "dropdown_example"
    title = "@string/title_preference"
    ...//entries and entries values same as ListPrefernces
}
..
To use a Seek bar Preference, you can use the SeekBarPrefernce tag in your XML file:
  <SeekBarPreference
            app:key="key_preference_seekbar"
            app:title="Seekbar Preference"
            app:defaultValue="20"
            />
  • The app:defaultValue is used to set the default value of the SeekBar out of 100. 
  • You can change the maximum value i.e. instead of 100, you can set your maximum value by using app:max attribute.
To use the SeekBar programmatically, use the below code:
val seekBarPreference = SeekBarPreference(context).apply {
    key = "seekbar_example"
    title = "@string/title_preference"
    setDefaultValue(20)
}
..


Expandable Preferences

Sometimes, we just need not show all the preferences present in a category. 
So, instead of showing all the Preferences, just show some or none of them and if the user clicks on the Expandable Preference, then the Preference will be expanded and you will see the whole Preference list.

So, to use an Expandable Preference, all you need to do is just add the app:initialExpandedChildrenCount attribute in your PreferenceCategory and set the value to the number of Preferences that you want to show when the Preference is not expanded.

   <PreferenceCategory
        app:key="advanced"
        app:title="Learning Preferences"
        app:initialExpandedChildrenCount="1">

        <Preference
            app:key="expandable_example"
            app:title="Hello I am Simple text"
            app:summary="I am the preference that will be showed when the preference is not expanded"/>

        <Preference
            app:title="Bolt UIX"
            app:summary="Click me to open the Bolt UIX website">

            <intent android:action="android.intent.action.VIEW"
                android:data="https://www.boltuix.com/"/>

        </Preference>

        <SwitchPreferenceCompat
            app:key="parent"
            app:title="Newsletter"
            app:summary="You can turn me on/off i.e. you can toggle me!"/>

    </PreferenceCategory>
..


Using Preferences in our Project
After looking at various types of Preferences that can be used in Settings, let’s look at how we can display this on our Activity or simply let’s look at how to connect these XML files with our fragment.

package com.boltuix.androidpreferences

import android.content.SharedPreferences
import android.os.Bundle
import android.text.InputType
import android.util.Log
import android.view.inputmethod.EditorInfo
import androidx.preference.EditTextPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat

class SettingsFragment : PreferenceFragmentCompat(),
    SharedPreferences.OnSharedPreferenceChangeListener,
    Preference.OnPreferenceClickListener {

    companion object {
        private val TAG = SettingsFragment::class.java.simpleName
    }

    /**
     * A preference fragment that demonstrates commonly used preference attributes.
     */
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        //To display your Preference’s XML file, all you need to do is just use the setPreferencesFromResource(). For example:
        setPreferencesFromResource(R.xml.settings_preference, rootKey)

        preferenceManager.sharedPreferences!!.registerOnSharedPreferenceChangeListener(this)

        findPreference<Preference>("key_preference_nested")?.onPreferenceClickListener = this

        findPreference<EditTextPreference>("key_preference_edit_text")
            ?.setOnBindEditTextListener { editText ->
                editText.inputType = InputType.TYPE_TEXT_FLAG_CAP_WORDS
                editText.maxLines = 1
                editText.imeOptions = EditorInfo.IME_ACTION_DONE
            }
    }

    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
        Log.d(TAG, "on shared preferences changed..key: $key")

        when (key) {
            "key_preference_switch" -> {
                val value = sharedPreferences?.getBoolean(key, false)
                findPreference<Preference>("key_preference_switch_text")?.isVisible = value ?: false
                Log.d(TAG, "updated value: $value")
            }
            "key_preference_check_box" -> {
                val value = sharedPreferences?.getBoolean(key, false)
                Log.d(TAG, "updated value: $value")
            }
            "key_preference_seekbar" -> {
                val value = sharedPreferences?.getInt(key, -1)
                Log.d(TAG, "updated value: $value")
            }
            "key_preference_edit_text" -> {
                sharedPreferences?.getString(key, "")?.let { Log.d(TAG, "updated value: $it") }
            }
            "key_preference_list" -> {
                sharedPreferences?.getString(key, "")?.let { Log.d(TAG, "updated value: $it") }
            }
            "key_preference_multi_select_list" -> {
                sharedPreferences?.getStringSet(key, emptySet())
                    ?.let { Log.d(TAG, "updated value: $it") }
            }
        }
    }

    override fun onPreferenceClick(preference: Preference): Boolean {
        when (preference.key) {
            "key_preference_nested" -> {
                Log.d(TAG, "received click for key preference 3")
               // findNavController().navigate(R.id.action_nav_pref_setting_to_nested_setting)
            }
        }
        return true
    }
}

Finally, run your application on your mobile phone. You can use these Preference settings in your application.

GET source code on Github:

..

To create a Custom UI setting page ref below link


Comments