8

我一直在尝试让一个开关首选项在 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).
4

3 回答 3

7

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

为每个事件实现带有自定义操作的 switchpreference:

  • forevercrashed提出了一些好的观点。我试着跟随他们,但对我来说他们没有这样做。我敢打赌它们会起作用,但我需要以更简单的方式提供更多功能。Xgouchet(第二个链接)使用标题和自定义 xml 布局,这些布局使用自定义放置和测量(高度、宽度、填充等)。我需要一个解决方案,而无需更改 Google 内置的自动生成布局。

  • 超级简单而强大的方法:实现你自己的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 NOT调用callChangeListener(Object newValue)。现在您可以单击首选项并且什么都不会发生,直到您想要它。(否则会发生的一个错误是onPreferenceChange在片段中多次调用)


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

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

    • OnPreferenceChangeListener在首选项上添加
    • 我个人让我的片段实现监听器并this作为参数传递。
    • return 语句很重要。这就是使交换机发生实际变化的原因。如果您返回 true,则开关将更改为 newValue。如果您返回 false,则不会。如果您使用return false;,您可以在 switchpreference 上使用 setChecked(true|false) 更改该值。
  • 当您实现时,onPreferenceChange(Preference preference, Object newValue)您可以添加任何您想要的功能,只需按下开关滑块

  • 单击首选项的功能可以通过三种方式完成:
    • 在自定义类中实现onClick()进一步SwitchPreference
    • 实现onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)片段中的方法
    • onPreferenceClickListener像您为 ChangeListener 所做的那样实现。

对不起,如果这是一个很长的帖子。这是我的第一个,我已经浏览了很多关于这个的 stackoverflow 页面,没有人是准确的,只是想把它做对;)

于 2013-07-11T08:25:29.337 回答
2

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

鉴于我的问题,这是我选择的解决方案:如何使用 EditTextPreference 和 Togglebutton 创建一个首选项?

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

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

它将为您提供与上述几乎相同的外观和感觉,但需要更多的工作,并且由于我的要求对我不起作用。

于 2013-01-22T21:26:31.247 回答
1

我想你在问一个不存在的功能。

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

这是我基于此网站发布的关于自定义它的帖子。我问的是如何添加 listView ,但我不知道偏好活动实际上使用 listview 。

于 2013-01-18T22:06:38.977 回答