EditText追加空格、限制字符等

3,699 阅读4分钟

使用输入框时产品常常会有一些需求,比如123456789变成123-456-789或者限制一些字符的输入等等。很多时候都是网上搜索就完事了,但是每次都去搜索有点浪费时间,而且有些也不符合需求。所以自己写一篇,以后就可以吃老本了。😝

追加字符

借鉴博客EditText每4位自动添加空格

import android.content.Context;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;

import com.ifreegroup.ebbly.lib_common.utils.AppLogUtil;

/**
 * @Describe:自动添加占位符的输入框
 * @Date: 2019/06/11
 * @Author: dengkewu
 * @Contact:
 */
public class PlaceHolderEditText extends android.support.v7.widget.AppCompatEditText {
    //上次输入框中的内容
    private String lastString;
    //光标的位置
    private int selectPosition;
    //输入框内容改变监听
    private TextChangeListener listener;

    //追加字符
    private String item = "-";

    public PlaceHolderEditText(Context context) {
        super(context);
        initView();
    }

    public PlaceHolderEditText(Context context, AttributeSet attrs) {
        super(context, attrs);

        initView();
    }

    public PlaceHolderEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }


            /**
             * 当输入框内容改变时的回调
             * @param s  改变后的字符串
             * @param start 改变之后的光标下标
             * @param before 删除了多少个字符
             * @param count 添加了多少个字符
             */
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {


                //因为重新排序之后setText的存在
                //会导致输入框的内容从0开始输入,这里是为了避免这种情况产生一系列问题
                if (start == 0 && count > 1 && getSelectionStart() == 0) {
                    return;
                }

                String textTrim = getText().toString().trim();
                if (TextUtils.isEmpty(textTrim)) {
                    return;
                }

                //如果 before >0 && count == 0,代表此次操作是删除操作
                if (before > 0 && count == 0) {
                    selectPosition = start;
                    if (TextUtils.isEmpty(lastString)) {
                        return;
                    }
                    //将上次的字符串去空格 和 改变之后的字符串去空格 进行比较
                    //如果一致,代表本次操作删除的是空格
                    if (textTrim.equals(lastString.replaceAll(item, ""))) {
                        //帮助用户删除该删除的字符,而不是空格
                        StringBuilder stringBuilder = new StringBuilder(lastString);
                        stringBuilder.deleteCharAt(start - 1);
                        selectPosition = start - 1;
                        setText(stringBuilder.toString());
                    }
                } else {
                    //此处代表是添加操作
                    //当光标位于空格之前,添加字符时,需要让光标跳过空格,再按照之前的逻辑计算光标位置
                    if ((start + count) % 5 == 0) {
                        selectPosition = start + count + 1;
                    } else {
                        selectPosition = start + count;
                    }
                }
            }


            @Override
            public void afterTextChanged(Editable s) {
                //获取输入框中的内容,不可以去空格
                String etContent = getText().toString();
                if (TextUtils.isEmpty(etContent)) {
                    if (listener != null) {
                        listener.textChange("");
                    }
                    return;
                }
                //重新拼接字符串
                String newContent = addSpaceByCredit(etContent);
                //保存本次字符串数据
                lastString = newContent;

                //如果有改变,则重新填充
                //防止EditText无限setText()产生死循环
                if (!newContent.equals(etContent)) {
                    setText(newContent);
                    try {
                        //保证光标的位置
                        setSelection(selectPosition > newContent.length() ? newContent.length() : selectPosition);
                    } catch (Exception e) {
                    //刚好为限制字符的整数倍时添加空格后会出现越界的情况
                        //AppLogUtil.e("超过限制字符");
                    }

                }
                //触发回调内容
                if (listener != null) {
                    listener.textChange(newContent);
                }

            }
        });
    }


    /**
     * 输入框内容回调,当输入框内容改变时会触发
     */
    public interface TextChangeListener {
        void textChange(String text);
    }

    public void setTextChangeListener(TextChangeListener listener) {
        this.listener = listener;

    }

    /**
     * 每4位添加一个空格
     *
     * @param content
     * @return
     */
    public String addSpaceByCredit(String content) {
        if (TextUtils.isEmpty(content)) {
            return "";
        }
        content = content.replaceAll(item, "");
        if (TextUtils.isEmpty(content)) {
            return "";
        }
        StringBuilder newString = new StringBuilder();
        for (int i = 1; i <= content.length(); i++) {
            if (i % 4 == 0 && i != content.length()) {
                newString.append(content.charAt(i - 1) + item);
            } else {
                newString.append(content.charAt(i - 1));
            }
        }
        return newString.toString();
    }

    /**
     * 获取追加字符前输入内容
     * @return
     */
    public String getInputText() {
        return getText().toString().replaceAll(item, "");
    }
}

  核心思路是在文本改变时获取到原字符串取出每一个字符添加上要追加的字符后返回字符串并重新setText。当然中间会有一些坑,比如光标位置、删除时空格要跳过以及删除后会再追加空格会造成死循环的问题。当然这里很多情况已经处理过了,如果有其他需求比如手机号码的111 1111 1111的形式可以修改addSpaceByCredit这个方法。

限制字符

借鉴博客Android EditText限制输入字符的5种实现方式

   et_traveler_content.addTextChangedListener(new TextWatcher() {
               @Override
               public void beforeTextChanged(CharSequence s, int start, int count, int after) {

               }

               @Override
               public void onTextChanged(CharSequence s, int start, int before, int count) {
                   String editable = et_traveler_content.getText().toString();
                   String str = stringFilter(editable.toString());
                   if (!editable.equals(str)) {
                       et_traveler_content.setText(str);
                       //设置新的光标所在位置
                       et_traveler_content.setSelection(et_traveler_content.getText().toString().length());
                   }
               }

               @Override
               public void afterTextChanged(Editable s) {

               }
           });
           
    
   public String stringFilter(String str) {
       // 只允许字母、数字、英文空白字符
       String regEx = "[^a-zA-Z0-9\\s]";
       Pattern p = Pattern.compile(regEx);
       Matcher m = p.matcher(str);
       return m.replaceAll("");
   }

  这里也是输入时做过滤然后重新setText。只要需要对正则表达式熟悉想做什么限制都可以。

MD效果

系统自带

      <android.support.design.widget.TextInputLayout
                   android:layout_width="match_parent"
                   android:layout_height="match_parent"
                   android:layout_marginStart="15dp"
                   android:padding="0dp"
                   android:layout_centerVertical="true"
                   android:gravity="center_vertical">

                   <EditText
                     …… />
               </android.support.design.widget.TextInputLayout>

只需要用TextInputLayout包裹一层便可以实现MD效果。

常用属性

1.明文、密文

    if (isShowPwd) {
          // 可视密码输入
          setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo
                  .TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
      } else {
          // 非可视密码状态
          setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
      }

2.默认不获取焦点

父容器设置(其实只要布局内有一个控件设置就可以)

android:focusableInTouchMode="true"

一些第三方库


最开始坚持的地方,记录学习与生活的点点滴滴