Android 具有自定义布局的SwitchPreference侦听器

Android 具有自定义布局的SwitchPreference侦听器,android,preferencefragment,android-switch,Android,Preferencefragment,Android Switch,我试图在设置页面中使用SwitchPreference,但无法让侦听器正常工作。我使用自定义小部件布局来设置开关的样式,因为我找不到如何使用主题来实现这一点。在my settings.xml中,我有以下内容: <SwitchPreference android:key="uitestmode" android:summary="Enable to display test data in fragments" andr

我试图在设置页面中使用SwitchPreference,但无法让侦听器正常工作。我使用自定义小部件布局来设置开关的样式,因为我找不到如何使用主题来实现这一点。在my 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>
以及我的交换机的自定义布局:

<?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" />


我遇到的问题是,当我单击开关时,侦听器没有被调用。有人知道为什么以及如何修复吗?

我遇到了同样的问题,我的解决方案与以下类似:

  • 在自定义交换机布局中,添加以下代码。这将“揭示”首选项,并使整个块可单击。这就是为什么侦听器根本不会被触发

    android:clickable=“false” android:focusable=“false”

  • 扩展“SwitchPreference”,并在“onBindView”类中,从SharedReferences获取状态,并在其中处理开关状态的更改

    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);
                }
            }
        }
    }
    
    public类MySwitchPreference扩展了SwitchPreference{
    公共MySwitchPreference(上下文){
    super(上下文,null);
    }
    公共MySwitchPreference(上下文、属性集属性){
    超级(上下文,attrs);
    }
    公共MySwitchPreference(上下文、属性集属性、int-defStyle){
    超级(上下文、属性、定义样式);
    }
    受保护的void onBindView(视图){
    //在调用SwitchPreference.onBindView之前清除侦听器
    ViewGroup ViewGroup=(ViewGroup)视图;
    clearListenerInViewGroup(视图组);
    super.onBindView(视图);
    最终开关mySwitch=(开关)view.findViewById(R.id.custom\u开关\u项);
    Boolean initVal=this.getPersistedBoolean(false);
    if(initVal){
    mySwitch.setChecked(true);
    }
    this.setOnPreferenceChangeListener(新的OnPreferenceChangeListener(){
    @凌驾
    公共布尔onPreferenceChange(首选项首选项,对象newValue){
    //在这里做你的事情,拨动开关等等
    返回true;
    }
    });
    }
    私有void clearListenerInViewGroup(视图组视图组){
    如果(null==viewGroup){
    返回;
    }
    int count=viewGroup.getChildCount();
    对于(int n=0;n

  • 希望这能帮助你。直到我用这种方法解决了这个问题,我才找到任何解决方案。

    –根据答案,但同时适用于Switch和SwitchCompat。

    SwitchView的id应该是
    @android:id/Switch\u widget
    ,而不是
    @+id/custom\u Switch\u item
    或任何其他自定义id

    SwitchPreference
    类的源代码中,我们可以找到以下代码:

    View-switchView=View.findviewbyd(AndroidResources.ANDROID\R\u-SWITCH\u小部件);
    
    AndroidResources
    中:

    static final int-ANDROID\u-R\u-SWITCH\u WIDGET=ANDROID.R.id.SWITCH\u WIDGET;
    
    因此,只有id=
    @android:id/switch\u小部件才能正确找到

    下面是关于SwitchPreference的widgetLayout的演示:

    
    
    嘿,里克凯斯,我用过这个,你觉得这个解决方案很有魅力。但是我想要一些额外的功能。不确定我是否需要为它制作一个新的主题,但可能是Nelson b。奥斯汀也想要这个。我想要的是我的偏好在点击时改变(你的改变是什么),而且是可滑动的,让这个改变成为我的偏好。通过将android:clickable更改为true,可以使其可滑动。但是他的计划破坏了你以前的解决方案。你知道怎么做吗?亲切问候,,Jeroen@Jeroen我自己没有机会尝试,但我想你可能想尝试以下几点:1。将android:clickable设置为true。2.设置为开关,并手动更新首选项。这可能会有帮助。谢谢,这就是解决方案
    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);
                }
            }
        }
    }