切换首选项 - 处理onPreferenceChange和onPreferenceClick

时间:2013-01-18 20:58:59

标签: android preferences listeners

我一直在尝试在Android中使用切换首选项,我可以截取和处理不同的内容,在某些情况下,当他们打开/关闭时,与他们点击整个首选项时相比。

这就是我想要完成的事情: 用户进入首选项标签已关闭且未存储任何标签(即:标签首选项为空) 用户打开标签的首选项,由于当前没有存储标签,因此它会启动标签搜索活动以供用户查找标签。 - 工作正常。

如果标签已存在,并且它们仅更改状态,则正常更新该值。 - 工作正常

这是我的问题: 如果他们单击首选项并且他们已经保存了标记,请不要更改状态(无论是启用还是禁用),启动标记搜索活动。 - 这不起作用。

到目前为止我发现的是,在上面的最后一个场景中,我调用onPreferenceChanged,然后调用onPreferenceClicked,然后调用onPreferenceChanged。这似乎是我的问题。对onPreferenceChanged的第一次调用导致我的SharedPreferences上的监听器被调用,告诉它现在已经启用了。

如果我没有收到onPreferenceChanged的第一个电话,那么我就不会有问题。

以下是我正在设置监听器的相关部分

SwitchPreference tagPref = (SwitchPreference) findPreference(PreferencesConstants.PREFERENCE_TAG_ENABLED);
    tagPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {

        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            Log.e("BLAH", "onPrefChanged....is it handled by OnClick?" + Boolean.toString(handledByClick));


            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());

            boolean enabled = prefs.getBoolean(PreferencesConstants.PREFERENCE_TAG_ENABLED, false);
            Log.e("BLAH", "value stored in prefs? " + Boolean.toString(enabled));
            if (newValue instanceof Boolean) {
                enabled = (Boolean) newValue;
            }

            Log.e("BLAH", "New value? " + Boolean.toString(enabled));

            if (!handledByClick) {
                if (enabled && (currentTag == null || currentTag.isEmpty())) {
                    Log.e("BLAH", "Enabled and CurrentTag empty!");
                    Intent intent = new Intent(getActivity(), TagSearchActivity.class);
                    startActivityForResult(intent, 0);

                    return false; // always return false, we'll handle
                                    // updating
                                    // this value manually.
                } else {
                    return true;
                }
            }
            Log.e("BLAH", "returning false (AS IN WE HANDLED IT).");
            return false;
        }
    });

    tagPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {

        @Override
        public boolean onPreferenceClick(Preference preference) {

            handledByClick = true;
            Log.e("BLAH", "onprefClick");

            Intent intent = new Intent(getActivity(), TagSearchActivity.class);
            startActivityForResult(intent, 0);

            return true;
        }
    });

以下是使用已保存标记运行并点击首选项后的相关日志行。

01-18 15:55:05.593: E/BLAH(13261): onPrefChanged....is it handled by OnClick?false
01-18 15:55:05.593: E/BLAH(13261): value stored in prefs? true
01-18 15:55:05.593: E/BLAH(13261): New value? false
01-18 15:55:05.613: E/DifferentClass(13261): On Shared Preferences Changed - tagEnabled
01-18 15:55:05.652: E/DifferentClass(13261): disabled TAG in cancelAlarmService
01-18 15:55:05.662: E/AnotherClass(13261): Updating Feed List.  Old Size: 33, New Size: 14
01-18 15:55:05.682: E/BLAH(13261): onprefClick
01-18 15:55:05.812: E/BLAH(13261): onPrefChanged....is it handled by OnClick?true
01-18 15:55:05.812: E/BLAH(13261): value stored in prefs? false
01-18 15:55:05.822: E/BLAH(13261): New value? false
01-18 15:55:05.822: E/BLAH(13261): returning false (AS IN WE HANDLED IT).

3 个答案:

答案 0 :(得分:7)

我多年来一直在处理同样的问题,你可以用两种方式解决这个问题。

为每个事件实施自定义操作的切换首选项:

  • forevercrashed提出了一些好处。我试着跟着他们,但对我来说他们没有这样做。我打赌他们工作,但我需要更简单的功能。 Xgouchet(第二个Link)使用Headers和自定义xml布局,它使用自定义放置和测量(高度,厚度,填充等)。我需要一个解决方案,而不需要改变以自动生成的布局构建的谷歌。

  • 超级简单而强大的方式:实现自己的SwitchPreference! 只需使一个类扩展SwitchPreference,然后像这样实现/覆盖:

    public class AutoUploadSwitchPreference extends SwitchPreference {
    public AutoUploadSwitchPreference(Context context) {
        super(context);
    }
    public AutoUploadSwitchPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public AutoUploadSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    
    @Override
    protected void onClick() {
        //super.onClick(); THIS IS THE IMPORTANT PART!
    }
    

覆盖onClick()并注释/删除super.onClick()会使SwitchPreference 调用callChangeListener(Object newValue)。现在,您可以单击首选项,但没有任何反应,直到您想要它。 (否则会发生一个错误就是在片段中多次调用onPreferenceChange


现在!让事情发生:这是我用过的结构。

  • 创建SettingsActivity
    • 确保您获取偏好,资源等。
  • 在您的活动的onCreate()
  • - 启动PreferenceFragment
    • 这需要是一个扩展PreferenceFragment的自定义类,请参阅此处:PreferenceFragment
  • 在自定义片段中,获取自定义偏好设置。您可以使用findPreference("custom_switch_key")

    • 在偏好
    • 上添加OnPreferenceChangeListener
    • 我个人让我的片段实现了监听器并传递this作为参数。
    • 退货声明很重要。这就是交换机实际变化的原因。如果返回true,则开关将变为newValue。如果你返回false,它就不会。如果您使用return false;,则可以在switchpreference上使用setChecked(true | false)更改该值。
  • 实施onPreferenceChange(Preference preference, Object newValue)时,只需按下开关滑块即可添加所需功能

  • 点击偏好的功能可以通过三种方式完成:
    • 在自定义onClick()
    • 中进一步实施SwitchPreference
    • 在片段
    • 中实施方法onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)
    • 像为ChangeListener一样实施onPreferenceClickListener

很抱歉,如果这是一篇很长的帖子。这是我的第一次,我经历过这么多关于此的stackoverflow页面,并没有人准确,只是想把它弄好;)

答案 1 :(得分:2)

在搜索了几个小时后,我发现了一些在这种情况下对其他人有帮助的帖子。

这是我选择的解决方案:How do I create one Preference with an EditTextPreference and a Togglebutton?

这是一个非常详细的答案,对理解偏好很有帮助。

我遇到的另一篇文章就是这篇文章:http://xgouchet.fr/android/index.php?article4/master-on-off-preferences-with-ice-cream-sandwich

它会给你几乎与上面相同的外观和感觉,但需要更多的工作,因为我的要求对我不起作用。

答案 2 :(得分:1)

我认为你在询问一个不存在的功能。

但是,由于首选项活动使用了listView,您可以使用一些技巧来自定义它并按照您的意愿处理它。

here's a post我根据this website制作了自定义内容。我问的是如何添加listView,但我不知道偏好活动实际上使用了listview。