Слушатель SwitchPreference с пользовательской разметкой

Я пытаюсь использовать SwitchPreference на своей странице настроек, но не могу заставить слушателя работать. Я использую пользовательский макет виджета для стилизации переключателя, так как не могу найти, как использовать темы для этого. В моем файле settings.xml у меня есть следующее:

<SwitchPreference
            android:key="uitestmode"
            android:summary="Enable to display test data in fragments"
            android:title="UI Test Mode"
            android:widgetLayout="@layout/widget_custom_switch_on_off" >
</SwitchPreference>

и мой SettingsFragment выглядит так:

SwitchPreference uiTestModePref = (SwitchPreference) findPreference("uitestmode");
uiTestModePref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        Log.d(preference.getKey(), newValue.toString());
        return false;
    }
});

и мой пользовательский макет для моего переключателя:

<?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:textOn="On"
    android:textOff="Off"
    android:textStyle="bold"
    android:thumb="@drawable/carcast_switch_inner_holo_dark"
    android:track="@drawable/carcast_switch_track_holo_dark" />

У меня проблема в том, что когда я нажимаю на переключатель, слушатель не вызывается. Кто-нибудь знает почему и как это исправить?

2 ответа

Я столкнулся с той же проблемой, мое решение похоже на следующее:

  1. В свой собственный макет переключателя добавьте следующий код. Это "раскрывает" предпочтение и делает весь блок кликабельным. Вот почему слушатель не срабатывает вообще.

    android: clickable = "false" android: focusable = "false"

  2. Расширьте "SwitchPreference" и в классе "onBindView" получите состояния от SharedPreferences и обработайте изменения состояний переключателей.

    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);
                }
            }
        }
    }
    

Надеюсь, это поможет вам. Я не смог найти никакого решения для своего случая, пока не понял это таким образом.

Решение - основано на ответе RickCase, но работает как с Switch, так и с SwitchCompat.

Идентификатор SwitchView должен быть @android:id/switch_widget вместо того @+id/custom_switch_item или любой другой пользовательский идентификатор.

В источнике SwitchPreference class, мы можем найти код:

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

И в AndroidResources:

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

так что только id = @android:id/switch_widget можно найти правильно.

Вот демонстрация widgetLayout SwitchPreference:

<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" />
Другие вопросы по тегам