【问题标题】:Switch Preference - Handling both onPreferenceChange and onPreferenceClick切换首选项 - 处理 onPreferenceChange 和 onPreferenceClick
【发布时间】:2013-01-02 16:05:29
【问题描述】:

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

【问题讨论】:

    标签: android preferences listeners


    【解决方案1】:

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

    然而,由于偏好活动使用 listView,您可以使用一些技巧来自定义它并按照您的意愿处理它。

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

    【讨论】:

    • 感谢您的链接...在搜索了几个小时后,我设法找到了发布到 SO 的此问题的副本。我将把它作为答案,所以如果其他人看到这篇文章,他们会找到合适的解决方案。 (也很简单!)
    【解决方案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

    它将为您提供与上述几乎相同的外观和感觉,但需要更多的工作,因为我的要求不适合我。

    【讨论】:

    • 非常好的帖子。谢谢你展示它。您仍然可以像我一样自定义偏好。请注意,我上次检查时,自定义首选项存在一些问题,以防它们存在于 android 库中。不知道是什么以及为什么。也许他们已经固定在最新的 ADT&SDK 上。
    • 另外,我刚刚意识到要获得开关偏好的“真实”外观和感觉,您需要结合我上面发布的 2 个链接中的一些内容。虽然第一个链接是我实现的,但我意识到布局文件只有一个标题,没有摘要。我需要标题和摘要。我发布的第二个链接有一个非常好的布局文件,它正是这样做的。我仍然需要更改一些填充和文本大小,以使其看起来与我的设置屏幕中的其他首选项相同......以防万一有人需要此信息。
    【解决方案3】:

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

    为每个事件实现带有自定义操作的 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) 时,您只需按下开关滑块即可添加您想要的任何功能

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

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

    【讨论】:

    • 您的偏好活动代码也会很有帮助。使用可检查小部件(开关、复选框等)实现任何类型偏好的整体良好解决方案。
    • @Yokich,谢谢。这在我的 Moto X (API 4.4.4) 上效果很好,但不幸的是,在 Nexus 4 (API 5.0) 上不起作用。根据Android源代码(SwitchPreference中的Listener类),它应该可以工作,但N4仍然只在按下开关时注册onPreferenceClick。有什么想法吗?
    • 我真的没有任何答案给你,对不起。希望你能找到你要找的东西
    猜你喜欢
    • 2020-04-14
    • 2015-07-13
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-13
    • 1970-01-01
    相关资源
    最近更新 更多