3

I try to get custom switch preference in adroid. Here is my code

 switch_widget.xml
<Switch xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/customswitch"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:focusable="false"
   android:clickable="false" 
   />
  preference xml file :
 <com.tnavitech.utils.CustomSwitch
       android:title="Hide app icon" 
       android:key="hideicon"
       android:defaultValue="false"
       android:disableDependentsState="true"
       android:widgetLayout="@layout/switch_widget" 
    />

Then I extend "SwitchPreference", and in "onBindView" class, and handle switch states in OnPreferenceChangeListener :

public class CustomSwitch extends SwitchPreference {

    Switch swit;

    public CustomCheckbox(Context context, AttributeSet attrs) {
    super(context, attrs);

   }

@Override
protected void onBindView(final View rootView) {
    ViewGroup viewGroup= (ViewGroup)rootView;
    super.onBindView(rootView);

    if(swit==null){

        swit  = (Switch) rootView.findViewById(R.id.customswitch);
    }

    this.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference arg0, Object arg1) {

            if (arg1 instanceof Boolean) {
                Boolean enabled = (Boolean) arg1;
                if(enabled){
                    swit.setChecked(true); /// cant toggle switch here
                    Toast.makeText(getContext(), "on", Toast.LENGTH_SHORT).show();


                } else {
                    Toast.makeText(getContext(), "off", Toast.LENGTH_SHORT).show();

                    swit.setSelected(false);     ///cant toggle switch here
            }
            }



            return true;
        }
    });

}

In setOnPreferenceChangeListener i cant toggle the swith on or off. How could I solve this? Thanks!

user3693265
  • 109
  • 1
  • 9
  • In your code, arg0 points to the control triggering the listener. Instead of swit.setChecked, cast arg0 to the proper preference type and then call setChecked from there. Answer provided below for more detail. – J E Carter II Jan 14 '20 at 17:04

3 Answers3

1

Duplicate of SwitchPreference Listener with Custom Layout.

The id of SwitchView should be @android:id/switch_widget instead of @+id/custom_switch_item or any other custom id.

In the source of SwitchPreference class, we can find the code:

View switchView = view.findViewById(AndroidResources.ANDROID_R_SWITCH_WIDGET);

and in AndroidResources:

static final int ANDROID_R_SWITCH_WIDGET = android.R.id.switch_widget;

so only id = @android:id/switch_widget can be found correctly.

Here's a demo about SwitchPreference's widgetLayout:

<Switch xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/switch_widget"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_vertical" />
Chenhe
  • 924
  • 8
  • 19
0

I'm working on app running on a device with API 15 so had to fix this issue. The solution is about to have two different layouts for your SwitchPreference instead of one that handles switch toggling. Switch needs to be clickable = false otherwise your SwitchPreference won't handle any clicks.

First is 'on state' switch layout, where button uses drawable that represents ON button:

<?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="48dp"
    android:layout_height="wrap_content"
    android:textColor="@android:color/white"
    android:textIsSelectable="false"
    android:textSize="0sp"
    android:button="@drawable/ico_toggle_on" //HERE IS DIFFERENCE BETWEEN THESE LAYOUTS
    android:thumb="@android:color/transparent"
    android:track="@android:color/transparent"
    android:clickable="false"
    android:focusable="false"
    android:gravity="center_vertical" />

Second layout is for OFF state:

<?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="48dp"
    android:layout_height="wrap_content"
    android:textColor="@android:color/white"
    android:textIsSelectable="false"
    android:textSize="0sp"
    android:button="@drawable/ico_toggle_off" //HERE IS DIFFERENCE BETWEEN THESE LAYOUTS
    android:thumb="@android:color/transparent"
    android:track="@android:color/transparent"
    android:clickable="false"
    android:focusable="false"
    android:gravity="center_vertical" />

And then finally in your Activity or Fragment set on your SwitchPreference OnPreferenceChangeListener to switch these two layouts like this:

final SwitchPreference expertSettingsPref = (SwitchPreference) findPreference("expert_settings");
    if (expertSettingsPref != null) {
        expertSettingsPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                preference.setWidgetLayoutResource((Boolean)newValue ? R.layout.custom_switch_preference_on : R.layout.custom_switch_preference_off);
                return true;
            }
        });
    }
Honza Musil
  • 320
  • 2
  • 10
0

Using SwitchPreferenceCompat with androidX within a PreferenceFragmentCompat, the following works as you request.

public class SettingsPageFragment extends PreferenceFragmentCompat {
    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.root_preferences, rootKey);

        final SwitchPreferenceCompat switchPreference = (SwitchPreferenceCompat) findPreference("switch");
        if(switchPreference != null){
            switchPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    // get the incoming value
                    boolean isOn = (Boolean) newValue;

                    // get the incoming control
                    SwitchPreferenceCompat switchPreference = (SwitchPreferenceCompat) preference;

                    // set the incoming value to the incoming control
                    switchPreference.setChecked(isOn);

                    // do whatever else you wanted to when this event fires

                }
            });
        }
    }

I suspect the reason your code is not working is that 'swit' may be out of scope for the listener. It is passed in as Preference preference in my example.

J E Carter II
  • 1,436
  • 1
  • 22
  • 39