How can a list of radio buttons be shown within a PreferenceSecreen
rather than in a dialog? It's really annoying having to click more than once just to select an item from this list.
Expected result
Current result
app_preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:key="prefPhotoFilter"
android:title="Photo filter"
android:entries="@array/photoFilters" />
</PreferenceScreen>
strings.xml
<string-array name="photoFilters">
<item name="1">Natural</item>
<item name="2">Boosted</item>
<item name="3">Saturated</item>
</string-array>
According to this Gist, you can extend CheckBoxPreference and create a layout with a radio button.
Like this: First, create a new layout containing an only radio button let's call it
preference_widget_radiobutton.xml
<?xml version="1.0" encoding="utf-8"?>
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="false"
android:focusable="false" />
then create a subclass of CheckBoxPreference:
class RadioButtonPreference : CheckBoxPreference {
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) { setView() }
constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs) { setView() }
private fun setView(){
widgetLayoutResource = R.layout.preference_widget_radiobutton
}
override fun onClick() {
if (this.isChecked)
return
super.onClick()
}
}
in your app_preferences.xml
screen:
<PreferenceCategory android:title="Photo Filters">
<Your_class_package_dirctory.RadioButtonPreference
android:key="naturals"
android:title="Natural" />
<Your_class_package_dirctory.RadioButtonPreference
android:key="boosted"
android:title="Boosted" />
<Your_class_package_dirctory.RadioButtonPreference
android:key="saturated"
android:title="Saturated" />
</PreferenceCategory>
Now as you can see this will behave like normal CheckBox, it won't get uncheck the previous radio button, to solve this issue:
In your preference screen code:
class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceClickListener{
private val sharedPreference = AppPreferences()
private var oldCheckedPreference: RadioButtonPreference? = null
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.app_preferences, rootKey)
findPreference<RadioButtonPreference>("naturals")?.apply {
/*
You can set the defualt button to be checked by:
updateCheckedRadioButton(this)
*/
onPreferenceClickListener = this@SettingsFragment
}
findPreference<RadioButtonPreference>("boosted")?.onPreferenceClickListener = this
findPreference<RadioButtonPreference>("saturated")?.onPreferenceClickListener = this
}
private fun updateCheckedRadioButton(radioButtonPreference: RadioButtonPreference) {
//Uncheck the previous selected button if there is.
oldCheckedPreference?.isChecked = false
radioButtonPreference.isChecked = true
oldCheckedPreference = radioButtonPreference
}
override fun onPreferenceClick(preference: Preference): Boolean {
if (preference is RadioButtonPreference)
updateCheckedRadioButton(preference)
return true
}
}
and the result is: