关于 app 开启 talkback 模式,界面上的数字串无法正确播报数字(播报成了金额)的解决方法

27 篇文章 1 订阅
21 篇文章 0 订阅

项目场景:

根据工信部的要求,APP 需要做适老化改造,让长辈或者视障人士在使用 app 时能更加方便,体验更好,其中一个改造点就是用户开启了手机的 talkback 模式后,app 能否正确播报相关内容,给视障人士/长辈提供正确的反馈和使用引导。


问题描述:

改造过程中,有这样一个场景,用户开启了 talkback 模式,单击数字串的文本或者输入了数字的输入框,播报的内容不正确。

例如:

1、输入框,输入了验证码:123456,talkback 播报为:“十二万三千四百五十六”;

2、文本框,例如手机号:18925012345,银行卡号等,也都会播报成金额

这样的体验明显是不好的,播报内容反馈给用户也是不正确的。


解决方案:

一、TextView

针对 TextView 文本的,我的解决方案是重写了 TextView,给 TextView 的每个字符之间设置了空格,就可以实现 talkback 播报不把数字串当成金额播报,当然 TextView 也有设置字符边距的属性:

android:letterSpacing

这个我试过了没有效果,依旧会播报成金额,大概是因为它只是增加了字符之间的距离而不是在中间插入空格,没有实现隔断。

下面是我重写的 TextView 的代码,用法和 TextView 一样。

public class LetterSpacingTextView extends TextView {


    private float spacing = Spacing.NORMAL;
    private CharSequence originalText = "";

    public LetterSpacingTextView(Context context) {
        super(context);
    }

    public LetterSpacingTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LetterSpacingTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * 获取字间距
     *
     * @return
     */
    public float getSpacing() {
        return this.spacing;
    }

    /**
     * 设置间距
     *
     * @param spacing
     */
    public void setSpacing(float spacing) {
        this.spacing = spacing;
        applySpacing();
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        originalText = text;
        applySpacing();
    }

    @Override
    public CharSequence getText() {
        return originalText;
    }

    /**
     * 添加应用空间
     */
    private void applySpacing() {
        if (this == null || this.originalText == null) return;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < originalText.length(); i++) {
            builder.append(originalText.charAt(i));
            if (i + 1 < originalText.length()) {
                // \u00A0 不间断空格
                // 追加空格
                builder.append("\u00A0");
            }
        }
        
        // 通过这个,去设置空格
        SpannableString finalText = new SpannableString(builder.toString());
        if (builder.toString().length() > 1) { // 如果当前TextView内容长度大于1,则进行空格添加
            for (int i = 1; i < builder.toString().length(); i += 2) { // 小demo:100  1 0 0
                // 按照x轴等比例进行缩放 通过我们设置的字间距+1除以10进行等比缩放
                finalText.setSpan(new ScaleXSpan((spacing + 1) / 10), i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
        super.setText(finalText, TextView.BufferType.SPANNABLE);
    }

    public class Spacing {
        public final static float NORMAL = 0;
    }

}

二、EditText

针对 EditText,我的解决方案也是给数字串中间插入空格,不过没有重写 EditText,直接在 TextWatcher 的 onTextChange() 方法中执行插入空格。

这样写要解决一个点,就是当用户移动光标进行输入/删除操作时,计算好整个字符数组的下标位置。废话不多说,上代码:

private void editTextMatchTalkBack(CharSequence s, int start, int before, int count) {
        if (s == null || s.length() == 0) return;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == ' ') {
                continue;
            } else {
                //当做删除操作,并且删除的是空格时,它前面的字符不做 append,达到删除空格相当于删除字符的目的
                if (before == 1 && count == 0 && start - 1 >= 0 && s.charAt(start - 1) != ' ' && i == start - 1) {
                    continue;
                } else {
                    builder.append(s.charAt(i));
                    if (i != s.length() - 1) {
                        builder.append(' ');
                    }
                }

            }
        }

        if (builder.charAt(builder.length() - 1) == ' ') {
            builder.deleteCharAt(builder.length() - 1);
        }

        //让 builder 和 s 变得相等,不再触发 onTextchange(), 达到最终字符串显示的目的
        if (!builder.toString().equals(s.toString())) {
            edt_identifying_code.setText(builder.toString());
            //如果是输入
            if (before == 0) {
                if (start == s.length() - 1) {
                    edt_identifying_code.setSelection(builder.toString().length());
                } else {
                    edt_identifying_code.setSelection(start + 2);
                }
            } else {
                //如果是删除
                if (start - 1 < 0) {
                    edt_identifying_code.setSelection(0);
                } else {
                    edt_identifying_code.setSelection(start - 1);
                }
            }

        }
    }

这样基本上就解决了数字文本播报成金额的问题,方法是笨方法,如果大家有更好的方法也希望不吝赐教。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高钙小新

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值