Custom Layout For Android Preference

April 6, 2018

Android Preference allow overriding 2 type of layout:

  • android:layout: The layout for the entire Preference (include title, summary and widget)

  • android:widgetLayout: The layout for the controllable widget portion of a Preference (e.g. a checkbox preference would specify a custom layout consisting of just the CheckBox here)

Custom layout

Technically you can overide the entire layout of Preference, but I think you should treat this approach as the last resort. Reason being your layout might different in style (size, margin, etc.) from other preference.

If possible, you should create a custom layout without overriding the layout (e.g. Android Preference With Icon On Right Side of Title )

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

    <CheckBoxPreference
        android:layout="@layout/preference_pro_switch"
        android:defaultValue="true"
        android:key="test"
        android:title="Test"
        />

</PreferenceScreen>

Content of R.layout.preference_pro_switch.

Example of Preference layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="?android:attr/selectableItemBackground"
    android:baselineAligned="false"
    android:clipToPadding="false"
    android:gravity="center_vertical"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
    android:paddingRight="?android:attr/listPreferredItemPaddingRight">

    <RelativeLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingBottom="16dp"
        android:paddingTop="16dp"
        >

        <TextView
            android:id="@android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:singleLine="true"
            android:textAppearance="?android:attr/textAppearanceListItem"
            android:textSize="16sp"
            tools:text="Title" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toEndOf="@android:id/title"
            android:layout_toRightOf="@android:id/title"
            android:layout_marginLeft="8dp"
            android:tint="@color/icon_tint"
            app:srcCompat="@drawable/ic_delete_black_24dp"
            />

        <TextView
            android:id="@android:id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@android:id/title"
            android:layout_alignStart="@android:id/title"
            android:layout_below="@android:id/title"
            android:maxLines="2"
            android:paddingTop="6dp"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="?android:attr/textColorSecondary"
            android:textSize="14sp"
            tools:text="Summary" />

    </RelativeLayout>

    <Switch
        android:id="@android:id/checkbox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@null"
        android:clickable="false"
        android:focusable="false"
        />
</LinearLayout>

Widget layout

You can replace the widget portion of a Preference with a View, such as a Button or ImageView.

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

    <Preference
        android:layout="@layout/preference_button_widget"
        android:defaultValue="123"
        android:key="test"
        android:title="Test"
        />

</PreferenceScreen>

Content of R.layout.preference_button_widget.

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/button" 
    android:text="My Button" 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />

If you need to access the button (custom widget), you would need to create a custom Preference class (Refer to Android Preference With Icon On Right Side of Title as an example).

class CustomPreference : Preference {
    ...

    override fun onBindView(view: View) {
        super.onBindView(view)
        val button = view.findViewById(R.id.button) as Button
    }
}

References:

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.