android EditText中插入tag

android EditText中插入tag

最近项目上有一个需求,需要实现一个类似于csdn选择标签的功能:

android EditText中插入tag_第1张图片

下面是最终的效果:

android EditText中插入tag_第2张图片

采用edittext图文混标的思路,在edittext中插入图片,这样可以实现一次添加,一次删除。
edittext中插入的图片可以是bitmap,也可以是drawable。因为drawable的可塑性比较强,而且tag中的内容是动态的,所以我选择了drawable来做处理

新建一个类继承drawable

public class TagDrawable extends Drawable {

@Override
public void draw(@NonNull Canvas canvas) {
    //TODO 画图
}

@Override
public void setAlpha(int i) {
    //TODO 设置画笔的透明度
}

@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
    //TODO 设置画笔的颜色过滤器
}

@Override
public int getOpacity() {
    return PixelFormat.TRANSLUCENT;
}

}

给tag的属性建立一个实体类

一个tag包含了多种属性,比如文本颜色,大小,背景颜色等。。。。,所以需要一个实体类来保存

public class Tag {

    private int bgColor;
    private int textColor;
    private String text;
    private float textSize;

    Tag(Builder builder) {
        this.bgColor = builder.bgColor;
        this.textColor = builder.textColor;
        this.text = builder.text;
        this.textSize = builder.textSize;
    }

    public void setBgColor(int bgColor) {
        this.bgColor = bgColor;
    }

    public int getBgColor() {
        return bgColor;
    }

    public void setTextColor(int textColor) {
        this.textColor = textColor;
    }

    public int getTextColor() {
        return textColor;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public void setTextSize(float textSize) {
        this.textSize = textSize;
    }

    public float getTextSize() {
        return textSize;
    }

    public static class Builder {
        private int bgColor;
        private int textColor;
        private String text;
        private float textSize;

        public Builder bgColor(int bgColor) {
            this.bgColor = bgColor;
            return this;
        }

        public Builder textColor(int textColor) {
            this.textColor = textColor;
            return this;
        }

        public Builder text(String text) {
            this.text = text;
            return this;
        }

        public Builder textSize(int textSize) {
            this.textSize = textSize;
            return this;
        }

        public Tag build() {
            return new Tag(this);
        }
    }

}

属性的名称都写的比较见名知意,这儿就不解释了。

开始画图

这里写图片描述

参考这张图我们可以很清楚的知道其实需要绘制的就两个部分
1.背景(圆角矩形)
2.前端的文字

绘制之前需要先搞定以下几件事:
1.初始化画笔和数据(Tag实体类)
2.计算drawable的宽高
drawable的宽高是由文字的大小来决定的。
宽度要比文字的宽度多一点,因为两边要留一些空隙
高度是文字高度的1.5倍

//测量文字的宽高
Rect textRect = new Rect();
textPaint.getTextBounds(text, 0, text.length(), textRect);
//背景宽度要比文字宽度宽一些
width = textRect.width() + (textRect.width() / text.length() * 2);
//背景高度是文字高度的1.5倍
height = (int) (textRect.height() * 1.5);
3.文字居中显示
    我们有时候会发现android的文字会自带“margin”,因为需要考虑到“h”,‘g’这种特殊一点的字符,如果直接设置Paint.Align.CENTER属性是不会居中的
    具体的代码如下:
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
int baseLineY = (int) (rectF.centerY() - top / 2 - bottom / 2);//基线中间点的y轴计算公式
canvas.drawText(text, rectF.centerX(), baseLineY, textPaint);

搞定了以上几个需求,代码写起来就比较简单了,我这儿贴一下完整的代码(不足的地方请指正)

public class TagDrawable extends Drawable {

    private Paint bgPaint;
    private Paint textPaint;
    private int width;
    private int height;
    private String text;
    private Tag tag;

    TagDrawable(Tag tag) {
        init(tag);
    }

    private void init(Tag tag) {
        //初始化数据
        this.tag = tag;
        this.text = tag.getText();
        if (TextUtils.isEmpty(text))
            return;
        int bgColor = tag.getBgColor() == 0 ? Color.CYAN : tag.getBgColor();
        int textColor = tag.getTextColor() == 0 ? Color.BLACK : tag.getTextColor();
        float textSize = tag.getTextSize() == 0 ? 40 : tag.getTextSize();

        //背景画笔
        bgPaint = new Paint();
        bgPaint.setAntiAlias(true);
        bgPaint.setStyle(Paint.Style.FILL);
        bgPaint.setColor(bgColor);

        //文字画笔
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setColor(textColor);
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setTextSize(textSize);

        //测量文字的宽高
        Rect textRect = new Rect();
        textPaint.getTextBounds(text, 0, text.length(), textRect);
        //背景宽度要比文字宽度宽一些
        width = textRect.width() + (textRect.width() / text.length() * 2);
        //背景高度是文字高度的1.5倍
        height = (int) (textRect.height() * 1.5);
    }

    @Override
    public void draw(@NonNull Canvas canvas) {
        Rect rect = getBounds();

        //画背景(圆角矩形框)
        RectF rectF = new RectF(getBounds());
        rectF.bottom = height;
        //留出8px空白,以免添加多个tag时出现挤在一起的情况
        rectF.right = rectF.right - 8;
        canvas.drawRoundRect(rectF, 360, 360, bgPaint);

        int count = canvas.save();
        canvas.translate(rect.left, rect.top);

        //画文字(居中)
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
        float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
        int baseLineY = (int) (rectF.centerY() - top / 2 - bottom / 2);//基线中间点的y轴计算公式
        canvas.drawText(text, rectF.centerX(), baseLineY, textPaint);
        canvas.restoreToCount(count);
    }

    @Override
    public void setAlpha(int i) {
        textPaint.setAlpha(i);
    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {
        textPaint.setColorFilter(colorFilter);
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    @Override
    public int getIntrinsicWidth() {
        return width;
    }

    @Override
    public int getIntrinsicHeight() {
        return height;
    }

    @Override
    public void setBounds(int left, int top, int right, int bottom) {
        //设置drawable的宽高
        super.setBounds(left, top, width, height);
    }

    /**
     * 改变tag的状态
     *
     * @param tag
     */
    public void invalidateDrawable(Tag tag) {
        init(tag);
        invalidateSelf();
    }

    public Tag getTag() {
        return tag;
    }
}

使用方式

在插入图片的时候实际上也是对字符串的插入,如果这张图代表一个空字符串是没有意义的。我们先给定一张图实际代表的内容,然后再用drawable去替换

1.先生成一个随机内容的TagDrawable

/**
     * 随机获取一个tag
     * @return
     */
    private TagDrawable getRandomTagDrawable() {
        String text = Math.random() + "";
        Tag tag = new Tag.Builder().bgColor(Color.RED).text(text).textColor(Color.BLACK).textSize(60).build();
        TagDrawable tagDrawable = new TagDrawable(tag);
        //drawable在使用前需要重新测量宽高
        tagDrawable.setBounds(0, 0, tagDrawable.getIntrinsicWidth(), tagDrawable.getIntrinsicHeight());
        return tagDrawable;
    }

2.进行插入操作

/**
     * 插入一个tag
     * @param view
     */
    public void insert(View view) {
        TagDrawable randomTagDrawable = getRandomTagDrawable();

        ImageSpan imageSpan = new ImageSpan(randomTagDrawable, ImageSpan.ALIGN_BASELINE);
        String tempDrawableText = randomTagDrawable.getTag().getText();
        SpannableString spannableString = new SpannableString(tempDrawableText);
        //用drawable替换相应的文字
        spannableString.setSpan(imageSpan, 0, tempDrawableText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        int index = editText.getSelectionStart();
        Editable editableText = editText.getEditableText();
        if (index < 0 || index > editText.getText().length()) {
            editableText.append(spannableString);
        } else {
            editableText.insert(index, spannableString);
        }

        System.out.println("length==============" + editText.getText().toString().length());

    }

如果我们在每次插入后获取内容的长度,你会发现drawable的长度就就是他所代表内容的长度

(完)

你可能感兴趣的:(android EditText中插入tag)