SwitchPreference customization – use analysis

Introduction to SwitchPreference

SwitchPreference is a UI component in Android, which is used to display the switch button in the setting interface of the application, and allows the user to toggle the state of some functions or options. SwitchPreference inherits from Preference class, so it can be used in PreferenceScreen like other preferences. When the user toggles the state of the toggle button, the app can use the OnPreferenceChangeListener listener to catch the state change event and update the app’s settings accordingly.

What is Preference Screen?

PreferenceScreen is a UI component in Android that provides a structured way to present an application’s setting options. It is a subclass of the Preference class and can contain multiple instances of the Preference class, such as CheckBoxPreference, EditTextPreference, etc. When the user clicks an option in the PreferenceScreen, it will enter a new PreferenceScreen or open a Dialog for the user to make corresponding settings.

When implementing PreferenceScreen, you need to use the PreferenceScreen tag in the layout file, as follows:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Contains multiple instances of the Preference class -->
</PreferenceScreen>

In java code, you can use PreferenceFragment or PreferenceActivity to manage PreferenceScreen.

PreferenceFragment is a Fragment that can be added to an Activity. In PreferenceFragment, you can load a PreferenceScreen layout file by calling the addPreferencesFromResource(int) method. For example:

public class MyPreferenceFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}

PreferenceActivity is an Activity that inherits from ListActivity. In PreferenceActivity, you can load a PreferenceScreen layout file by calling the addPreferencesFromResource(int) method. For example:

public class MyPreferenceActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}

It should be noted that starting from Android 11, it is recommended to use PreferenceFragmentCompat instead of PreferenceFragment. PreferenceFragmentCompat is a compatibility library that can be used in Android 4.0 and above.

Custom SwitchPreference layout

Dem: An activity contains a PreferenceScreen, and there is a SwitchPreference in the PreferenceScreen. The SwitchPreference uses a custom layout, and from left to right are switch, title, icon

Define a custom layout “custom_switch_preference.xml”

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:gravity="center_vertical"
    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">

    <Switch
        android:id="@android:id/switch_widget"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="false"
        android:clickable="false"
        android:layout_gravity="center_vertical" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center_vertical"
        android:layout_marginStart="16dp">

        <TextView
            android:id="@ + android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceListItem"
            android:textColor="?android:attr/textColorPrimary"
            android:singleLine="true"
            android:ellipsize="marquee" />

        <TextView
            android:id="@ + android:id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
            android:textColor="?android:attr/textColorSecondary"
            android:singleLine="true"
            android:ellipsize="marquee" />

    </LinearLayout>

    <ImageView
        android:id="@ + android:id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:layout_gravity="center_vertical" />

</LinearLayout>

Create a PreferenceScreen file using this custom layout:

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

    <SwitchPreference
        android:key="switch_preference"
        android:title="Switch Preference"
        android:icon="@drawable/ic_launcher"
        android:widgetLayout="@layout/custom_switch_preference" />

</PreferenceScreen>

Finally, load this PreferenceScreen in your Activity: slightly

Operation result:

Question: The order of the layout is the opposite of what we want?

Reason: The pictures and text displayed here are set in PreferenceScreen, not in custom layout. The button is in a custom layout

Modification scheme: custom SwitchPreference

Custom SwitchPreference

Create a custom SwitchPreference

public class CustomSwitchPreference extends SwitchPreference {


    private Drawable drawable;
    private String title;

    public CustomSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        setWidgetLayoutResource(R.layout.custom_switch_preference);
    }

    public CustomSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public CustomSwitchPreference(Context context, AttributeSet attrs) {
        this(context, attrs, android. R. attr. switchPreferenceStyle);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomSwitchPreference);
        title = a.getString(R.styleable.CustomSwitchPreference_title);
        drawable = a.getDrawable(R.styleable.CustomSwitchPreference_icon);
        a. recycle();
    }

    public CustomSwitchPreference(Context context) {
        this(context, null);
    }

    @Override
    protected void onBindView(View view) {
        super.onBindView(view);
        TextView titleView = view.findViewById(R.id.title);
        ImageView iconView = view.findViewById(R.id.icon);
        if (titleView != null) {
            titleView.setText(title);
        }
        if (iconView != null) {
            iconView.setImageDrawable(drawable);
        }
    }
}

Add custom attributes in the attrs.xml file:

<resources>
    <declare-styleable name="CustomSwitchPreference">
        <attr name="title" format="string" />
        <attr name="icon" format="reference" />
    </declare-styleable>
</resources>

Modify the PreferenceScreen file to use this custom SwitchPreference: and delete the title and icon attributes

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <com.example.mvvm.preference.CustomSwitchPreference
        android:key="example_switch_preference"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        app:title = "cherry"
        app:icon = "@drawable/cherry"
        android:defaultValue="true" />
</PreferenceScreen>

operation result