自定义EditView实现同步显示输入的字符长度

在日常开发中有时需要实现在一个输入框中输入字并且同步显示已输入字符的长度,以方便查看此输入框最大能输入多少字符,现在已输入多少字符。实现效果如下:


1516330704071mz效果图.gif

主要实现步骤及相关代码:
1.首先创建一个类继承EditText,实现构造方法;
2.定义相关属性:在《项目名称》\src\main\res\values\attrs.xml文件中:

 <declare-styleable name="WordsNumEditText">
        <attr name="numTextGravity" format="enum">
            <enum name="left" value="1" />
            <enum name="right" value="2" />
        </attr>
        <attr name="numTextSize" format="dimension" />
        <attr name="numTextColor" format="color" />

3.初始化设置的相关属性:

/**
     * @param context
     * @param attrs   初始化属性
     */
    private void initAttribute(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.WordsNumEditText);
        try {
            mNumTextSize = (int) ta.getDimension(R.styleable.WordsNumEditText_numTextSize, DensityUtils.sp2px(context, 12));//字体大小
            mNumTextColor = ta.getColor(R.styleable.WordsNumEditText_numTextColor, Color.parseColor("#b1b1b1"));//字体颜色
            grivity = ta.getInt(R.styleable.WordsNumEditText_numTextGravity, grivity);//显示的位置,left从左向右扩展,right从右向左扩展显示,
            maxLength = getMaxLength();//获取设置的最大显示字数
            paddingLeft = getPaddingLeft();
            paddingRight = getPaddingRight();
            bottom = DensityUtils.dip2px(context, 10);
            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom() + DensityUtils.dip2px(context, 10));
        } finally {
            ta.recycle();
        }
      initPaint();//初始化画笔
    
    }

其中获取editText的maxLength属性值的方法详情如下:

 /**
     * @return length
     * 获取editText的MaxLength的属性值
     */
    public int getMaxLength() {
        int length = 0;
        try {
            InputFilter[] inputFilters = this.getFilters();
            for (InputFilter filter : inputFilters) {
                Class<?> c = filter.getClass();
                if (c.getName().equals("android.text.InputFilter$LengthFilter")) {
                    Field[] f = c.getDeclaredFields();
                    for (Field field : f) {
                        if (field.getName().equals("mMax")) {
                            field.setAccessible(true);
                            length = (Integer) field.get(filter);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return length;
    }

3.初始化画笔,需根据设置的grivity属性确定画笔滑动的方向:

 /**
     * 创建一个画笔
     *
     * @param paintColor 画笔颜色
     * @param textSize   文字大小
     * @param style      画笔样式
     * @param roundWidth 画笔宽度
     * @return
     */
    private Paint createLeftPaint(int paintColor, int textSize, Paint.Style style, int roundWidth) {
        Paint paint = new Paint();
        paint.setColor(paintColor);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(roundWidth);
        paint.setDither(true);
        paint.setTextSize(textSize);
        paint.setTextAlign(Paint.Align.LEFT);//这是grivity为left的时候,若grivity是right,则设置为 Paint.Align.RIGHT
        paint.setStyle(style);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeJoin(Paint.Join.ROUND);
        return paint;
    }

4.在onDraw()中实现画“数字”的逻辑:

 /**
     * @param canvas 画输入框中 字数/最大字数
     */
    private void drawNumberText(Canvas canvas) {

        int length = getText().length();
        String str = length + "/" + maxLength;
        int x = 0;
        if (grivity == GRAVITY_LEFT) {
            x = 0 + paddingLeft;
        } else {
            x = width - paddingRight;
        }
        int y = height - bottom;
        canvas.drawText(str, x, y, textPaint);
    }

其中width和height需要在onMeasure()中实时计算:

 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
    }

最后附上完整代码及demo地址(名称有些繁琐,莫见怪哈):https://github.com/ErieCorner/DesplayInputCharacterLengthEdittextModule.git

public class DeplayInputCharacterLenghtEditText extends EditText {
    public DeplayInputCharacterLenghtEditText(Context context) {
        super(context);
        initAttribute(context, null);
    }

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

    public DeplayInputCharacterLenghtEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttribute(context, attrs);
    }

    private int mNumTextColor = Color.parseColor("#b1b1b1");
    private int mNumTextSize = 12;
    public final static int GRAVITY_LEFT = 1;//字数显示在左边,当数字位数增多时向右扩展
    public final static int GRAVITY_RIGHT = 2;//字数显示在右边,当数字位数增多时向左扩展
    private int grivity = GRAVITY_RIGHT;
    private Context context;
    private Paint textPaint;
    private int width;
    private int height;
    private int maxLength;
    private int paddingLeft = 0;
    private int paddingRight = 0;
    private int bottom = 0;

    /**
     * 初始化画笔
     */
    private void initPaint() {
        if (grivity == GRAVITY_LEFT) {
            textPaint = createLeftPaint(mNumTextColor, mNumTextSize, Paint.Style.FILL, 2);
        } else {
            textPaint = createRightPaint(mNumTextColor, mNumTextSize, Paint.Style.FILL, 2);
        }

    }

    /**
     * @param context
     * @param attrs   初始化属性
     */
    private void initAttribute(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DeplayInputCharacterLenghtEditText);
        try {
            mNumTextSize = (int) ta.getDimension(R.styleable.DeplayInputCharacterLenghtEditText_numTextSize, DensityUtils.sp2px(context, 12));
            mNumTextColor = ta.getColor(R.styleable.DeplayInputCharacterLenghtEditText_numTextColor, Color.parseColor("#b1b1b1"));
            grivity = ta.getInt(R.styleable.DeplayInputCharacterLenghtEditText_numTextGravity, grivity);
            maxLength = getMaxLength();
        } finally {
            ta.recycle();
        }
        paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();
        bottom = DensityUtils.dip2px(context, 10);
        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom() + DensityUtils.dip2px(context, 10));
        initPaint();

    }


    /**
     * 判断是否为emoji表情
     *
     * @param codePoint 要校验的字符
     * @return 是否为表情
     */
    private boolean isEmojiCharacter(char codePoint) {
        return !((codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA) ||
                (codePoint == 0xD) || ((codePoint >= 0x20) && codePoint <= 0xD7FF)) ||
                ((codePoint >= 0xE000) && (codePoint <= 0xFFFD));
    }

    /**
     * 创建一个画笔
     *
     * @param paintColor 画笔颜色
     * @param textSize   文字大小
     * @param style      画笔样式
     * @param roundWidth 画笔宽度
     * @return
     */
    private Paint createLeftPaint(int paintColor, int textSize, Paint.Style style, int roundWidth) {
        Paint paint = new Paint();
        paint.setColor(paintColor);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(roundWidth);
        paint.setDither(true);
        paint.setTextSize(textSize);
        paint.setTextAlign(Paint.Align.LEFT);
        paint.setStyle(style);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeJoin(Paint.Join.ROUND);
        return paint;
    }

    /**
     * 创建一个画笔
     *
     * @param paintColor 画笔颜色
     * @param textSize   文字大小
     * @param style      画笔样式
     * @param roundWidth 画笔宽度
     * @return
     */
    private Paint createRightPaint(int paintColor, int textSize, Paint.Style style, int roundWidth) {
        Paint paint = new Paint();
        paint.setColor(paintColor);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(roundWidth);
        paint.setDither(true);
        paint.setTextSize(textSize);
        paint.setTextAlign(Paint.Align.RIGHT);
        paint.setStyle(style);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeJoin(Paint.Join.ROUND);
        return paint;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawNumberText(canvas);
    }

    /**
     * @param canvas 画输入框中 字数/最大字数
     */
    private void drawNumberText(Canvas canvas) {

        int length = getText().length();
        String str = length + "/" + maxLength;
        int x = 0;
        if (grivity == GRAVITY_LEFT) {
            x = 0 + paddingLeft;
        } else {
            x = width - paddingRight;
        }
        int y = height - bottom;
        canvas.drawText(str, x, y, textPaint);


    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        postInvalidate();
    }

    /**
     * @return length
     * 获取editText的MaxLength的属性值
     */
    public int getMaxLength() {
        int length = 0;
        try {
            InputFilter[] inputFilters = this.getFilters();
            for (InputFilter filter : inputFilters) {
                Class<?> c = filter.getClass();
                if (c.getName().equals("android.text.InputFilter$LengthFilter")) {
                    Field[] f = c.getDeclaredFields();
                    for (Field field : f) {
                        if (field.getName().equals("mMax")) {
                            field.setAccessible(true);
                            length = (Integer) field.get(filter);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return length;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355