Search code examples
androidandroid-switch

programmatically change color of Switch


I am trying to create a simple Custom Switch Widget that listens to changes in value of a certain key in SharedPreferences. Below is my code:

public class CustomSwitch extends SwitchCompat implements SharedPreferences.OnSharedPreferenceChangeListener {

    private static final String TAG = CustomSwitch.class.getSimpleName();

    private boolean isSwitchTintColorPrimary;

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

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

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

    private void initializeView(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomSwitch, 0, 0);
        try {
            isSwitchTintColorPrimary = ta.getBoolean(R.styleable.CustomSwitch_tintColorPrimary, false);
        } finally {
            ta.recycle();
        }
        applyTheme();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        registerThemeChangeListener();
    }

    private void registerThemeChangeListener() {
        if (getContext() != null)
            ColoriyoPreference.getSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        unRegisterThemeChangeListener();
    }

    private void unRegisterThemeChangeListener() {
        if (getContext() != null)
            ColoriyoPreference.getSharedPreferences(getContext()).unregisterOnSharedPreferenceChangeListener(this);
    }

    private void applyTheme() {
        ColorStateList thumbStates = new ColorStateList(
                new int[][]{
                        {android.R.attr.state_checked, android.R.attr.state_enabled},
                        {-android.R.attr.state_checked, android.R.attr.state_enabled},
                        {}
                },
                new int[]{
                        isSwitchTintColorPrimary ? ColoriyoPreference.getColor(getContext()) : ContextCompat.getColor(getContext(), R.color.colorPrimary),
                        ContextCompat.getColor(getContext(), R.color.grey_50),
                        ContextCompat.getColor(getContext(), R.color.grey_50)
                }
        );
        setThumbTintList(thumbStates);

        ColorStateList trackStates = new ColorStateList(
                new int[][]{
                        new int[]{-android.R.attr.state_enabled},
                        new int[]{}
                },
                new int[]{
                        Color.GRAY,
                        Color.LTGRAY
                }
        );
        setTrackTintList(trackStates);
        setTrackTintMode(PorterDuff.Mode.OVERLAY);
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (key.equals(PREFERENCE_KEY_COLOR)) {
            applyTheme();
        }
    }
}

And in layout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.chintansoni.android.themedemo.MainActivity"
    tools:showIn="@layout/activity_main">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.chintansoni.android.themedemo.customview.themeview.CustomTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TextView textColor"
            app:textColorPrimary="true" />

        <com.chintansoni.android.themedemo.customview.themeview.CustomButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button Background"
            app:backgroundColorPrimary="true" />

        <com.chintansoni.android.themedemo.customview.themeview.CustomSwitch
            android:id="@+id/switch_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textOff="Off"
            android:textOn="On"
            app:tintColorPrimary="true" />
    </LinearLayout>

    <uz.shift.colorpicker.LineColorPicker
        android:id="@+id/picker"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_margin="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:orientation="horizontal" />

</android.support.constraint.ConstraintLayout>

But my view is not getting rendered in UI. Also, I wonder if this code will listen to color change in preference and reflect the color change in runtime?

Any suggestion?


Solution

  • The only thing I was missing:

    public CustomSwitch(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.switchStyle); // <--- passing default Style Attribute 
    }
    

    My improved class is as below:

    public class CustomSwitch extends SwitchCompat implements SharedPreferences.OnSharedPreferenceChangeListener {
    
        private boolean isSwitchTintColorPrimary;
    
        public CustomSwitch(Context context) {
            this(context, null);
        }
    
        public CustomSwitch(Context context, AttributeSet attrs) {
            this(context, attrs, R.attr.switchStyle);
        }
    
        public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initializeView(context, attrs);
        }
    
        private void initializeView(Context context, AttributeSet attrs) {
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomSwitch, 0, 0);
            try {
                isSwitchTintColorPrimary = ta.getBoolean(R.styleable.CustomSwitch_tintColorPrimary, false);
            } finally {
                ta.recycle();
            }
            applyTheme();
        }
    
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            registerThemeChangeListener();
        }
    
        private void registerThemeChangeListener() {
            if (getContext() != null)
                ColoriyoPreference.getSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
        }
    
        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            unRegisterThemeChangeListener();
        }
    
        private void unRegisterThemeChangeListener() {
            if (getContext() != null)
                ColoriyoPreference.getSharedPreferences(getContext()).unregisterOnSharedPreferenceChangeListener(this);
        }
    
        private void applyTheme() {
            ColorStateList thumbStates = new ColorStateList(
                    new int[][]{
                            {android.R.attr.state_checked, android.R.attr.state_enabled},
                            {-android.R.attr.state_checked, android.R.attr.state_enabled},
                            {}
                    },
                    new int[]{
                            isSwitchTintColorPrimary ? ColoriyoPreference.getColor(getContext()) : ContextCompat.getColor(getContext(), R.color.colorPrimary),
                            ContextCompat.getColor(getContext(), R.color.grey_50),
                            ContextCompat.getColor(getContext(), R.color.grey_50)
                    }
            );
            setThumbTintList(thumbStates);
    
            ColorStateList trackStates = new ColorStateList(
                    new int[][]{
                            new int[]{android.R.attr.state_enabled},
                            new int[]{-android.R.attr.state_enabled}
                    },
                    new int[]{
                            Color.LTGRAY,
                            Color.GRAY,
                            Color.LTGRAY
                    }
            );
            setTrackTintList(trackStates);
        }
    
        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            if (key.equals(ColoriyoPreference.PREFERENCE_KEY_COLOR)) {
                applyTheme();
            }
        }
    }