Android: Creating custom preference

AndroidAndroid LayoutAndroid PreferencesPreferenceactivity

Android Problem Overview


Is it possible to create an individual preference in an PreferenceScreen?

I would like to code color settings like that:

Color Preference

I know that choosing the color is easy realizable with the ListPreference, but it would be awesome with that kind of "checkboxes".

Android Solutions


Solution 1 - Android

The Android Developer page only shows how to make a DialogFragment. It's still possible to customise the appearance of a Preference item though. In your XML you have to declare the root element as android:id="@android:id/widget_frame, and then declare TextView as android:title and android:summary. You can then declare other elements you want to appear in the layout. Here's an example showing a SeekBar which you could easily adapt to a multi-checkbox colour chooser.

seekbar_preference.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/widget_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@android:id/title"
        style="@android:style/TextAppearance.DeviceDefault.SearchResult.Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Title" />

    <TextView
        android:id="@android:id/summary"
        style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Summary" />
    
    <SeekBar
        android:id="@+id/seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Then, in a class that derives from Preference, override the onCreateView() method:

SeekbarPreference.java

@Override
protected View onCreateView( ViewGroup parent )
{
  LayoutInflater li = (LayoutInflater)getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
  return li.inflate( R.layout.seekbar_preference, parent, false);
}

Then in the preferences.xml file use the preference:

preferences.xml

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

    <com.example.SeekbarPreference
        android:key="pref_max_volume"
        android:title="@string/max_volume" />
    <com.example.SeekbarPreference
        android:key="pref_balance"
        android:title="@string/balance" />

</PreferenceScreen>

This gives a preference that looks as follows:

Seekbar preference item

You can easily adapt this method to show multiple checkboxes on a row as was in the original question.

Solution 2 - Android

This is how I do it, using support library preference-v7.

preference

layout/preference_theme.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <Button android:id="@+id/theme_light" ... />
    <Button android:id="@+id/theme_dark"... />
    <Button android:id="@+id/theme_sepia"... />
    <Button android:id="@+id/theme_green"... />
</LinearLayout>

PreferenceTheme.java (custom Preference class)

import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;

public class PreferenceTheme extends Preference {

    public PreferenceTheme(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PreferenceTheme(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setWidgetLayoutResource(R.layout.preference_theme);
    }

    @Override
    public void onBindViewHolder(PreferenceViewHolder holder) {
        super.onBindViewHolder(holder);
        holder.itemView.setClickable(false); // disable parent click
        View button = holder.findViewById(R.id.theme_dark);
        button.setClickable(true); // enable custom view click
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // persist your value here
            }
        });
        // the rest of the click binding
    }
}

preferences.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.preference.PreferenceCategory
        android:title="Reading">
        <example.com.preference.PreferenceTheme
            android:key="pref_theme"
            android:title="Theme"
            android:defaultValue="light" />
        ...
    </android.support.v7.preference.PreferenceCategory>
</android.support.v7.preference.PreferenceScreen>

Solution 3 - Android

Creating a custom preference is similar to creating a fragment or other UI components, by defining views and actions.

Android developers has a good guide on creating settings, which includes a section for creating custom preferences: http://developer.android.com/guide/topics/ui/settings.html#Custom

Solution 4 - Android

You can create your custom layout for preference and you can set it in android:layout attribute in Preference in res/xml like this:

<Preference
    ......................
    android:layout="@layout/your_layout" />

Or you can use an Activity instead of preference

Solution 5 - Android

Or a better alternative will be to extend the DialogPreference class. You can set a color picker widget as the dialog view and get the positive result inside the extended preference itself. Here is a similar question, but it is very useful for your scenario.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJonasView Question on Stackoverflow
Solution 1 - AndroidDaveView Answer on Stackoverflow
Solution 2 - AndroidhidroView Answer on Stackoverflow
Solution 3 - Androidtbkn23View Answer on Stackoverflow
Solution 4 - AndroidstinepikeView Answer on Stackoverflow
Solution 5 - AndroidC--View Answer on Stackoverflow