How to customize list preference radio button
Styling the ListPreference
from XML is not directly possible. The problem is that ListPreference
(through DialogPreference
) calls AlertDialog.Builder(Context)
to build its Dialog
, rather than AlertDialog.Builder(Context context, int themeResourceId)
. While the latter allows for providing a theme, the former does not, causing it to fall back to a default Android theme.
For a project, I needed a ListPreference
with a custom title-color, a custom radiobutton-style and a custom ListView-selector (basically, Holo in a different color). I solved this by extending ListPreference
and overriding onPrepareDialogBuilder(Builder)
and OnCreateDialogView()
so I could use a custom ListView with a simple ArrayAdapter, rather than Dialog
's built-in ListView
(which doesn't have support for styling). I also had to override onDialogClosed()
in order to set the right value to the preference.
In order to use it, all you have to do is replace the classname of the preference in your preferences.xml rom ListPreference
to com.your.packagename.ThemedListPreference
. Other than that, the implementation is identical to ListPreference.
public class ThemedListPreference extends ListPreference implements OnItemClickListener { public static final String TAG = "ThemedListPreference"; private int mClickedDialogEntryIndex; private CharSequence mDialogTitle; public ThemedListPreference(Context context, AttributeSet attrs) { super(context, attrs); } public ThemedListPreference(Context context) { super(context); } @Override protected View onCreateDialogView() { // inflate custom layout with custom title & listview View view = View.inflate(getContext(), R.layout.dialog_settings_updatetime, null); mDialogTitle = getDialogTitle(); if(mDialogTitle == null) mDialogTitle = getTitle(); ((TextView) view.findViewById(R.id.dialog_title)).setText(mDialogTitle); ListView list = (ListView) view.findViewById(android.R.id.list); // note the layout we're providing for the ListView entries ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>( getContext(), R.layout.btn_radio, getEntries()); list.setAdapter(adapter); list.setChoiceMode(ListView.CHOICE_MODE_SINGLE); list.setItemChecked(findIndexOfValue(getValue()), true); list.setOnItemClickListener(this); return view; } @Override protected void onPrepareDialogBuilder(Builder builder) { // adapted from ListPreference if (getEntries() == null || getEntryValues() == null) { // throws exception super.onPrepareDialogBuilder(builder); return; } mClickedDialogEntryIndex = findIndexOfValue(getValue()); // .setTitle(null) to prevent default (blue) // title+divider from showing up builder.setTitle(null); builder.setPositiveButton(null, null); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mClickedDialogEntryIndex = position; ThemedListPreference.this.onClick(getDialog(), DialogInterface.BUTTON_POSITIVE); getDialog().dismiss(); } @Override protected void onDialogClosed(boolean positiveResult) { // adapted from ListPreference super.onDialogClosed(positiveResult); if (positiveResult && mClickedDialogEntryIndex >= 0 && getEntryValues() != null) { String value = getEntryValues()[mClickedDialogEntryIndex] .toString(); if (callChangeListener(value)) { setValue(value); } } }}
For my ListView items I used the layout below. Note that drawable/btn_radio_holo_light is an XML-drawable like the one in your android-sdk/platforms/android-x/data/res/drawable folder, only with references to different drawables.
<?xml version="1.0" encoding="utf-8"?><CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:checkMark="@drawable/btn_radio_holo_light" android:gravity="center_vertical" android:minHeight="@dimen/list_item_minheight" android:paddingLeft="@dimen/list_item_paddingLeft" android:paddingRight="@dimen/list_item_paddingLeft" />
For my Dialog layout (onCreateDialogView()
), I used the following:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/dialog_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp" android:textColor="@color/title_color" android:textSize="22sp" /> <View android:layout_width="match_parent" android:layout_height="2dp" android:background="@color/divider_color" /> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:listSelector="@drawable/list_selector" /></LinearLayout>