使用InputFilter限制EditText时踩坑及解决方案

当我们想做EditText字符上的一些限制时,我们通常会用到InputFilter,通过重写里面的filter方法以做到限制长度的输入等,但是可能有心的同学会发现,在一些特定的情况下可能会发生字符取代覆盖的情况——比如我们用到特殊的输入法

//InputFilter接口,需要重写filter方法
public interface InputFilter
{
    /**
    * @param source 输入的文字
    * @param start 输入-0,删除-0
    * @param end 输入-source文字的长度,删除-0
    * @param dest 原先显示的内容
    * @param dstart 输入-原光标位置,删除-光标删除结束位置
    * @param dend  输入-原光标位置,删除-光标删除开始位置
    * @return
    */
    //主要重写这个方法
    public CharSequence filter(CharSequence source, int start, int end,
                               Spanned dest, int dstart, int dend);

    /**
     * This filter will capitalize all the lower case letters that are added
     * through edits.
     */
    //接口内的静态内部类,,,输入小写转换成大写
    public static class AllCaps implements InputFilter {
        public CharSequence filter(CharSequence source, int start, int end,
                                   Spanned dest, int dstart, int dend) {
            for (int i = start; i < end; i++) {
                if (Character.isLowerCase(source.charAt(i))) {
                    char[] v = new char[end - start];
                    TextUtils.getChars(source, start, end, v, 0);
                    String s = new String(v).toUpperCase();

                    if (source instanceof Spanned) {
                        SpannableString sp = new SpannableString(s);
                        TextUtils.copySpansFrom((Spanned) source,
                                                start, end, null, sp, 0);
                        return sp;
                    } else {
                        return s;
                    }
                }
            }
            return null; // keep original
        }
    }
    /**
     * This filter will constrain edits not to make the length of the text
     * greater than the specified length.
     */
    // 长度过滤器,限制输入的长度
    public static class LengthFilter implements InputFilter {
        private final int mMax;
        public LengthFilter(int max) {
            mMax = max;
        }
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
                int dstart, int dend) {
            int keep = mMax - (dest.length() - (dend - dstart));
            if (keep <= 0) {
                return ""; //主要问题出在这里,虽然inputfilter可以做输入过程中的长度限制,但是却不能对光标做任何的修改
            } else if (keep >= end - start) {
                return null; // keep original
            } else {
                keep += start;
                if (Character.isHighSurrogate(source.charAt(keep - 1))) {
                    --keep;
                    if (keep == start) {
                        return "";
                    }
                }
                return source.subSequence(start, keep);
            }
        }
        /**
         * @return the maximum length enforced by this input filter
         */
        public int getMax() {
            return mMax;
        }
    }
}

遇到这种与输入法相关的情况,我们就可以尝试另一种更灵活使用也更广泛的方法——Textwatcher,这个方法可以在输入时获取光标位置操作,更可以直接在输入时做出灵活的限制。具体操作可以参考下面一位大佬写的类。

package com.example.edittext;

import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;

/**
 * 自定义MyTextWatcher类实现TextWatcher接口,并重写相关方法
 * 
 * @author 邹奇
 *
 */
public class MyTextWatcher implements TextWatcher {

    private int limit;// 字符个数限制
    private EditText text;// 编辑框控件
    private Context context;// 上下文对象

    int cursor = 0;// 用来记录输入字符的时候光标的位置
    int before_length;// 用来标注输入某一内容之前的编辑框中的内容的长度

    public MyTextWatcher(EditText text, int limit,
            Context context) {
        this.limit = limit;
        this.text = text;
        this.context = context;
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        before_length = s.length();
    }

    /**
     * s 编辑框中全部的内容 、start 编辑框中光标所在的位置(从0开始计算)、count 从手机的输入法中输入的字符个数
     */
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        cursor = start;
//      Log.e("此时光标的位置为", cursor + "");
    }

    @Override
    public void afterTextChanged(Editable s) {
        // 这里可以知道你已经输入的字数,大家可以自己根据需求来自定义文本控件实时的显示已经输入的字符个数
        Log.e("此时你已经输入了", "" + s.length());

        int after_length = s.length();// 输入内容后编辑框所有内容的总长度
        // 如果字符添加后超过了限制的长度,那么就移除后面添加的那一部分,这个很关键
        if (after_length > limit) {

            // 比限制的最大数超出了多少字
            int d_value = after_length - limit;
            // 这时候从手机输入的字的个数
            int d_num = after_length - before_length;

            int st = cursor + (d_num - d_value);// 需要删除的超出部分的开始位置
            int en = cursor + d_num;// 需要删除的超出部分的末尾位置
            // 调用delete()方法将编辑框中超出部分的内容去掉
            Editable s_new = s.delete(st, en);
            // 给编辑框重新设置文本
            text.setText(s_new.toString());
            // 设置光标最后显示的位置为超出部分的开始位置,优化体验
            text.setSelection(st);
            // 弹出信息提示已超出字数限制
            Toast.makeText(context, "已超出最大字数限制", Toast.LENGTH_SHORT).show();
        }
    }

}

最后附上两位大佬的代码链接(狗头保命🐕🐕🐕

android的TextView的TextWatcher使用

Android开发中给EditText控件添加TextWatcher监听实现对输入字数的限制

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

麻辣璐璐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值