I\'m trying to use a SwitchPreference in my Settings page, but i can\'t get the listener to work. I am using a custom widget layout in order to style the switch, as I cannot
I ran into the same issue, my solution is similar to the followings:
In your custom switch layout, add following code. This "uncovers" the preference, and makes the whole block clickable. That's why the listener is not triggered at all.
android:clickable="false" android:focusable="false"
Extend "SwitchPreference", and in "onBindView" class, get states from SharedPreferences, and handle switch states change there.
public class MySwitchPreference extends SwitchPreference {
public MySwitchPreference(Context context) {
super(context, null);
}
public MySwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MySwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
protected void onBindView(View view) {
// Clean listener before invoke SwitchPreference.onBindView
ViewGroup viewGroup= (ViewGroup)view;
clearListenerInViewGroup(viewGroup);
super.onBindView(view);
final Switch mySwitch = (Switch) view.findViewById(R.id.custom_switch_item);
Boolean initVal = this.getPersistedBoolean(false);
if (initVal) {
mySwitch.setChecked(true);
}
this.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//Do your things here, toggling the switch and so on
return true;
}
});
}
private void clearListenerInViewGroup(ViewGroup viewGroup) {
if (null == viewGroup) {
return;
}
int count = viewGroup.getChildCount();
for(int n = 0; n < count; ++n) {
View childView = viewGroup.getChildAt(n);
if(childView instanceof Switch) {
final Switch switchView = (Switch) childView;
switchView.setOnCheckedChangeListener(null);
return;
} else if (childView instanceof ViewGroup){
ViewGroup childGroup = (ViewGroup)childView;
clearListenerInViewGroup(childGroup);
}
}
}
}
Hopefully this can help you. I was not able to find any solution for my case until I figured it out this way.
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" />
Solution – based on @RickCase answer, but works with both Switch and SwitchCompat.