You need to enable JavaScript to run this app. 如何使用android.text.InputType实现本地化数字输入及过滤异常解决
优惠活动
大模型
产品
解决方案
定价
更多

如何使用android.text.InputType实现本地化数字输入及过滤异常解决

核心问题定位

你遇到的输入无显示问题,本质是实现同时违反了InputFilter的运行规则、存在逻辑闭环缺陷,具体包括:

  • 完全搞错filter方法的返回值含义:该方法的返回值仅用于替换本次输入操作对应的source片段,而非替换整个EditText的文本。你现在把全量格式化后的本地化字符串作为返回值,完全偏离了系统的输入替换预期。
  • 解析逻辑存在致命缺陷:FarayanUtility.TryParseDouble仅能识别纯阿拉伯数字格式的字符串,但经过filter转换后的EditText文本已经是本地化数字(如波斯数字۱)。当系统插入本地化内容后,会自动对新插入的片段重新执行过滤,此时传入的source是本地化数字,解析直接返回null,触发filter返回空字符串,把刚插入的内容全部删除——这就是为什么你输入后完全看不到任何内容。
  • 后缀拼接逻辑错误:原代码中destSuffix = dend > 0 ? destText.substring(dend) : destText的判断没有任何依据,当光标位于文本起始位置(dend=0)时,会把整个原有文本作为后缀,打乱后续的解析文本拼接。
  • 无递归防护:由于返回的文本格式和用户输入的阿拉伯数字格式不一致,系统会反复触发filter调用,每次递归都会因为解析失败返回空,最终清空所有输入内容。
修复方案
  1. 调整解析逻辑:在拼接待解析文本时,先把已存在的dest文本、用户输入的source文本全部反向转换为标准阿拉伯数字,再做合法性校验,避免本地化数字导致的解析失败。
  2. 修正返回值逻辑:基于全量本地化后的展示文本,提取和本次输入替换区间对应的片段作为filter返回值,严格匹配系统的输入替换规则,不再返回全量文本。
  3. 修正后缀取值逻辑:去掉错误的dend > 0判断,统一取destText.substring(dend)作为替换区间之后的内容,保证拼接的待解析文本准确。
  4. 增加递归防护:当计算出的返回片段和原输入内容完全一致时,直接返回null(代表不修改本次输入内容),减少不必要的重复计算和递归触发。
参考修复代码
class LocalizedNumberInputFilter implements InputFilter {
    private final LocalNumberProvider localNumberProvider;

    public LocalizedNumberInputFilter(LocalNumberProvider provider) {
        this.localNumberProvider = provider;
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
        // 1. 拼接为标准阿拉伯数字格式的全量待校验文本
        String destRaw = dest.toString();
        String destNormalized = localNumberProvider.convertToLatinDigits(destRaw);
        String destPrefix = destNormalized.substring(0, dstart);
        // 修正原代码的后缀取值错误
        String destSuffix = destNormalized.substring(dend);
        String inputSegment = source.toString().substring(start, end);
        String inputNormalized = localNumberProvider.convertToLatinDigits(inputSegment);
        String fullNormalized = destPrefix + inputNormalized + destSuffix;

        // 2. 校验数字合法性,提前去掉千位分隔符避免解析失败
        String checkText = fullNormalized.replace(",", "");
        Double parsedValue = FarayanUtility.TryParseDouble(checkText);
        if (parsedValue == null) {
            // 非法输入直接拒绝,不允许插入
            return "";
        }

        // 3. 生成带分组的本地化展示文本
        NumberFormat numberFormat = NumberFormat.getInstance();
        numberFormat.setGroupingUsed(true);
        String groupedLatin = numberFormat.format(parsedValue);
        String fullLocalized = localNumberProvider.Localize(groupedLatin);

        // 4. 提取本次替换区间对应的返回片段,严格匹配InputFilter契约
        int prefixLength = localNumberProvider.Localize(destPrefix).length();
        String targetGrouped = groupedLatin.substring(destPrefix.length(), destPrefix.length() + inputNormalized.length());
        int segmentLength = localNumberProvider.Localize(targetGrouped).length();
        String returnSegment = fullLocalized.substring(prefixLength, prefixLength + segmentLength);

        // 5. 与原输入一致时直接返回null,避免递归触发
        if (returnSegment.contentEquals(inputSegment)) {
            return null;
        }
        return returnSegment;
    }
}
配套注意事项
  • 给LocalNumberProvider补充双向转换能力:除了已有的将阿拉伯数字转成本地化数字的Localize方法,必须新增反向转换方法convertToLatinDigits,用于把已输入的本地化数字转回标准格式供解析,否则第二次触发filter时依然会解析失败。
  • 不要在filter方法内直接调用EditText.setText()修改文本,所有的格式转换都必须通过filter的返回值实现,否则会触发无限递归的输入循环。
  • 解析数字时要提前把字符串里的千位分隔符去掉,否则带逗号的分组格式会导致TryParseDouble识别失败。

内容的提问来源于stack exchange,提问作者Homayoun Behzadian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.14 07:24:04