【问题标题】:How to create a preference that accepts only integer values如何创建只接受整数值的首选项
【发布时间】:2012-05-30 21:29:11
【问题描述】:

有没有办法在只接受整数值的 PreferenceFragment 中创建首选项?我可以实现一个 EditTextPreference 并注册一个 OnPreferenceChangeListener 如果用户输入一个不是数字的字符串,我可以在其中拒绝更改,但我更喜欢有意义的东西只保存数字并且不允许用户输入任何其他内容,可能只显示拨号盘键盘。我不存在这样的偏好,因为 Preference 的每个后代都映射到布尔值(CheckBoxPreference)、字符串 (*EditTextPreference) 或字符串数​​组 (MultiSelectListPreference),即没有首选项映射到整数,但也许你们中的一些人可以给我一个提示或至少告诉我是否有比我上面提出的更好的解决方案。

Grey 提出的解决方案:

EditText editText = ((EditTextPreference)    
                             findPreference("intent_property")).getEditText();
editText.setKeyListener(new NumberKeyListener() {
    @Override
    public int getInputType() {
        // The following shows the standard keyboard but switches to the view 
        // with numbers on available on the top line of chars
        return InputType.TYPE_CLASS_NUMBER;
        // Return the following to show a dialpad as the one shown when entering phone
        // numbers.
        // return InputType.TYPE_CLASS_PHONE
    }

    @Override
    protected char[] getAcceptedChars() {
        return new String("1234567890").toCharArray();
    }
});

更短的解决方案,不允许将键盘更改为拨号盘,但需要更少的代码:

EditText editText = ((EditTextPreference) 
                             findPreference("intent_property")).getEditText();
editText.setKeyListener(new DigitsKeyListener());

我不喜欢这个解决方案的一件事:用户可以输入 0000,它被接受并保存在共享首选项(它是一个字符串)中作为“0000”。这需要你实现一个 OnSharedPreferenceChangeListener 来拦截对共享首选项的更改并删除此首选项中的前导零或直接在此首选项上实现更改侦听器并返回 false 以拒绝带有尾随零的数字(告诉我是否有更好的解决方案来解决不涉及的最后一个问题实施您自己的偏好)。如果我们能修改OnPreferenceChangeListener中的newValue就更好了..

【问题讨论】:

  • 您如何以the source of EditTextPreference 为起点,将所有与字符串相关的方法换成基于int 的对应方法?对我来说似乎很简单。此外,从那时起,您将可以直接访问 EditText 对象,您可以根据自己的喜好设置任何仅限数字的输入类型。
  • @MH 如果我以编程方式管理首选项似乎很简单,但是如果我创建一个 EditTextIntegerPreference,例如,我不能在传递给的 XML 文件中使用它PreferenceFragment,或者有没有办法注册一个映射到我的新对象的新 XML 标记?
  • 您可以像使用自定义视图一样在 xml 文件中使用自定义首选项。只需提供完全限定的类名;例如com.costanzi.gianni.example.ExamplePreference。例如,请参阅this API demo
  • @MH 太棒了!感谢您提供有用的链接!
  • 感谢您撰写本文。它给了我一些关于如何处理我的 EditTextPreference 的线索。 :D

标签: android android-edittext android-preferences


【解决方案1】:

有一种更简单的方法可以做到这一点。只需在 XML 中的 EditTextPreference 中设置为 android:numeric="integer"(您可以将其设置为整数、有符号或小数)。

Eclipse(或您正在使用的任何工具)不会将此作为可能的属性显示给您,但只需将其写入您的 EditTextPreference 并清理您的项目。你会看到它不会给你任何错误。 :)

【讨论】:

    【解决方案2】:

    在阅读了建议的解决方案后,我仍然认为自定义偏好是要走的路。我确实以粗体字阅读了您的评论,但设置一个基本的EditTextIntegerPreference 实际上非常简单,它将解决您在用户输入例如“0000”时遇到的剩余问题。

    只是预先说明:因为您通常希望能够在应用程序的多个位置使用首选项,就我而言,EditTextIntegerPreference 的正确实现将针对@987654323 存储其值@。这样您就可以在任何地方检索 int 值,而无需先对其进行解析或强制转换。

    但是,为了使这个答案简明扼要,我实际上将展示常规 EditTextPreference 的扩展,这意味着在后台,该值仍将存储为字符串。如果您真的热衷于让“正确”的实现发挥作用,我不介意稍后再写。不过,它不应该太棘手,因此您可能想先自己尝试一下。 :)

    public class EditTextIntegerPreference extends EditTextPreference {
    
        private Integer mInteger;
    
        public EditTextIntegerPreference(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            getEditText().setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED);
        }
    
        public EditTextIntegerPreference(Context context, AttributeSet attrs) {
            super(context, attrs);
            getEditText().setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED);
        }
    
        public EditTextIntegerPreference(Context context) {
            super(context);
            getEditText().setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED);
        }
    
        @Override public void setText(String text) {
            final boolean wasBlocking = shouldDisableDependents();
            mInteger = parseInteger(text);
            persistString(mInteger != null ? mInteger.toString() : null);
            final boolean isBlocking = shouldDisableDependents(); 
            if (isBlocking != wasBlocking) notifyDependencyChange(isBlocking);
        }
    
        @Override public String getText() {
            return mInteger != null ? mInteger.toString() : null;
        }
    
        private static Integer parseInteger(String text) {
            try { return Integer.parseInt(text); }
            catch (NumberFormatException e) { return null; }
        }    
    }
    

    这解决了“0000”问题的原因是,我们只是在存储之前将用户键入的值转换为 int,然后在检索时将其插入到字符串中。这意味着任何前导零(当然除了“0”作为数字)都会自动消失。

    “数字”输入类型将限制用户只能输入数字,因此parseInteger(...) 方法主要是出于理智的原因而存在,尽管如果您尝试输入空或@987654328,它会捕获NumberFormatException @ 细绳。再说一次,你可以让这个更漂亮,我现在还没有这样做。

    【讨论】:

    • 非常感谢您为我花费的时间,您的示例非常清楚.. 我发现很奇怪他们没有为这样的偏好提供属性以便说“它必须只接受数字,在这种情况下它必须保存到整数/浮点数”,但是实现像你这样的解决方案并不太重。另一个可能的解决方案是监听属性变化,当该属性发生变化时,采取字符串值并强制转换为整数(删除前导零),因为我确信它只包含数字。
    • @Gianni Costanzi:关于您提到的其他可能的解决方案:这绝对是正确的,尽管为此设置一个专门的偏好类的好处是逻辑很好地自包含并从其他非- 相关代码。这一切都一样,所以取决于你。 :)
    • 你完全正确,恕我直言,你的解决方案更好,因为它是独立的......谢谢
    【解决方案3】:

    我猜你可以调用 getEditText() 来获取 EditText obj,然后使用 NumberKeyListener 调用 setKeyListener。

    【讨论】:

    • 我会尽快尝试,谢谢您的建议!
    • 我已经尝试了您告诉我的内容,并且效果很好,请查看我添加了这段代码的主要帖子。再次,非常感谢!
    • 如果您对上面编写的代码有进一步的建议,欢迎您!
    • 很抱歉这么多 cmets,但是 5 分钟的编辑时间对我来说太短了 :-/ 为什么我需要添加一个 NumberKeyListener 然后仍然必须指定我只想要数字?我也可以在我的 NumberKeyListener 中将字母作为 接受的字符 返回,它不会抱怨,所以我不清楚为什么会有一个 Text和一个Numeric KeyListener,有什么区别呢?他们是否在做一些他们两人之间不同的秘密工作? 编辑:也许我必须使用像 DigitsKeyListener 这样的直接子类,而不是 NumberKeyListener,对吧?
    • 我认为你的建议是正确的。假设有人使用了digitsKeyListener which accpet (- .),但他打算只使用(1-9),那么他不能使用digitskeylisente。但回退到 NumberKyeLisetner,并给出指定的字符集。但如果你不介意“负号或点”,你可以这样使用它。或者你想限制为只有 1-3 你只需要使用 NumberKeylisenter 对吗?
    【解决方案4】:

    您应该使用 PreferenceActivity,它基本上用于显示偏好设置,如 xml 文件。在此活动中,您可以使用复选框、编辑文本并将值保存到首选项。

    【讨论】:

    • 你能提供一个 OP 的示例 sn-p 吗?
    【解决方案5】:

    您也可以在尝试 parseInt() 数字后遇到异常时重新打开对话框。 这是一个示例代码:

    public class MyEditTextPreference extends EditTextPreference {
    
            private EditText _editText;
    
            public MyEditTextPreference(Context context, AttributeSet attrs) {
                super(context, attrs);
                _editText = getEditText();
            }
    
            @Override
            public void onDismiss(DialogInterface dialog) {
    
                super.onDismiss(dialog);
    
                try {
                    Integer.parseInt(_editText.getText().toString());
                } catch (NumberFormatException e) {
    
                    ((Dialog) dialog).show();
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-28
      相关资源
      最近更新 更多