Custom SwitchPreference in Android
Asked Answered
E

4

14

How to set a custom style or other background selector drawable for the SwitchPreference widget in Android?

(Note: not the regular Switch widget, I mean the standart SwitchPreference widget that used in PreferenceActivity / PreferenceFragment)

Elvyn answered 20/1, 2014 at 13:52 Comment(1)
This solution works for me. But only for API21+: https://mcmap.net/q/829153/-switchpreference-default-colorCuckoo
K
19

You have to create a custom layout for the switch itself and you can apply it dynamically like.

preference.setWidgetLayoutResource(R.layout.custom_switch);

But I'll go into details and show you exactly how to achieve this.

So, you define your preference in an xml file like preferences.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <PreferenceCategory android:title="YOUR_CATEGORY_TITLE" >
        <SwitchPreference
            android:key="SWITCH"
            android:title="YOUR_TITLE_FOR_SWITCH" />
    </PreferenceCategory>
</PreferenceScreen>

Then read it in the onCreate() method inside your PreferenceActivty class:

    SwitchPreference pref = (SwitchPreference) findPreference(getString(R.string.SWITCH));
    //pref.setChecked(true); // You can check it already if needed to true or false or a value you have stored persistently
    pref.setWidgetLayoutResource(R.layout.custom_switch); // THIS IS THE KEY OF ALL THIS. HERE YOU SET A CUSTOM LAYOUT FOR THE WIDGET
    pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {

        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            // Here you can enable/disable whatever you need to
            return true;
        }
    });

The custom_switch layout looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Switch xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/custom_switch_item"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:textColor="@android:color/white"
    android:textIsSelectable="false"
    android:textSize="18sp"
    android:textStyle="bold"
    android:track="@drawable/switch_track" 
    android:thumb="@drawable/switch_thumb"/>

And for the switch you'll have 2 selectors for the track and thumb properties. The drawables for these selectors can be generated with the Android Holo Color Generator, which was suggested by tasomaniac. In this case, all you have to do, is to copy the content of the generated drawable folders(only for the drawable-hdpi, drawable-mdpi, drawable-xhdpi, drawable-xxhdpi). But you can create custom views for each state you need.

Here is how these selectors will look like: switch_track:

<?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/switch_bg_focused" android:state_focused="true"/>
    <item android:drawable="@drawable/switch_bg"/>

</selector>

switch_thumb:

<?xml version="1.0" encoding="utf-8"?>
     <selector xmlns:android="http://schemas.android.com/apk/res/android">

     <item android:drawable="@drawable/switch_thumb_disabled" android:state_enabled="false"/>
     <item android:drawable="@drawable/switch_thumb_pressed" android:state_pressed="true"/>
     <item android:drawable="@drawable/switch_thumb_activated" android:state_checked="true"/>
     <item android:drawable="@drawable/switch_thumb"/>

</selector>

And that's pretty much it. This solution helped me out. If I omitted something, please let me know and I'll correct the issues.

Kinson answered 18/2, 2014 at 12:56 Comment(4)
The issue I am having with the solution is that the widget does not seem to represent the state of the sharedpreference value, i.e. it will never be checked / unchecked according to the sp and setCheck does not seem to change the UI as well. I reckon that's an issue with the Android version I am using (4.4.2)Hime
i can't handle any event of switch preferenceNaoise
@Hime - shared preferences are not mend to be changed via setChecked etc :) - if u want manually change sp widget u need to set preference via preference manager then redraw headers or reload view { by invalidate or getPreferenceScreen().removeAll(); addPreferencesFromResource(@IdRes int); }Drawl
This solution is not complete because in SwitchPreference.java, it searches for a widget with id "com.android.internal.R.id.switchWidget" which is not exposed by the SDK. So you need to copy the original SwitchPreference.Java and change that id to something you gave in the layoutSelfsuggestion
A
3

You can use the below website to generate style for your Switch. http://android-holo-colors.com/

And then you can use following libraries to custom implementation of the regular Switch. These libraries also include SwitchPreference alternative.

https://github.com/BoD/android-switch-backport

https://github.com/ankri/SwitchCompatLibrary

Antecedency answered 20/1, 2014 at 15:55 Comment(0)
S
2

One way of doing this is to subclass the SwitchPreference and override the onBindView method. In doing so, you'll want to still call super.onBindView(view) in that method, but then find the Switch in the child views and style it as appropriate:

package com.example;

import android.annotation.SuppressLint;
import android.content.Context;
import android.preference.SwitchPreference;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Switch;

import com.example.R;


public class CustomSwitchPreference extends SwitchPreference {

    @SuppressLint("NewApi")
    public CustomSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

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

    public CustomSwitchPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomSwitchPreference(Context context) {
        super(context);
    }

    @Override
    protected void onBindView(View view) {

        super.onBindView(view);
        Switch theSwitch = findSwitchInChildviews((ViewGroup) view);
        if (theSwitch!=null) {
            //do styling here
            theSwitch.setThumbResource(R.drawable.new_thumb_resource);
        }

    }

    private Switch findSwitchInChildviews(ViewGroup view) {
        for (int i=0;i<view.getChildCount();i++) {
            View thisChildview = view.getChildAt(i);
            if (thisChildview instanceof Switch) {
                return (Switch)thisChildview;
            }
            else if (thisChildview instanceof  ViewGroup) {
                Switch theSwitch = findSwitchInChildviews((ViewGroup) thisChildview);
                if (theSwitch!=null) return theSwitch;
            }
        }
        return null;
    }
}
Stouthearted answered 21/5, 2015 at 19:54 Comment(0)
L
0

Create a style in your style.xml file and give it Widget.AppCompat.CompoundButton.Switch parent.

<style name="theme_switch_compat" parent="Widget.AppCompat.CompoundButton.Switch">

    <item name="colorAccent">@color/YourColorAccent</item>

</style>

Then you can use the link below to complete your theme

How to change the track color of a SwitchCompat

Laure answered 22/4, 2021 at 12:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.