Android spanableString 实现 超链接替换为图文标识

Android spanableString 实现 超链接替换为图文标识,第1张

这是今年换工作的第一个需求,链接替换为标题


spanableString只有imagespan可以替换内容改为图片,但是不支持文字替换为文字或者图文文字

产品参考飞书都能做,搜索了一边,没找到好的方案,只能根据imagespan的原理,自己实现了一套方案出来,先贴代码把


/**
 * 正则找出的link text 替换为 icon+title方案,目前支持单行显示
 * 参考了.SpanUtils
 */
public class ImageTextSpan extends ReplacementSpan {
    private MarkBlock markBlock;
    @ColorInt
    private int color;
    private Drawable chatMsgLinkDrawable;

    private EditText editText;

    TextPaint textPaint = new TextPaint();

    public ImageTextSpan(EditText editText, MarkBlock markBlock, @ColorInt int color, Drawable chatMsgLinkDrawable) {
        //this.editText = editText;
        this.markBlock = markBlock;
        this.color = color;
        //设置这个setBounds
        chatMsgLinkDrawable.setBounds(0, 0, chatMsgLinkDrawable.getIntrinsicWidth(), chatMsgLinkDrawable.getIntrinsicHeight());
        this.chatMsgLinkDrawable = chatMsgLinkDrawable;
    }

    /**
     * @param paint
     * @param text
     * @param start
     * @param end
     * @param fontMetricsInt
     * @return
     */
    @Override
    public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fontMetricsInt) {
        Drawable drawable = chatMsgLinkDrawable;
        Rect rect = drawable.getBounds();
        text = text.subSequence(start, end);
        int width = -1;
        if (markBlock.getUrlTitle() == null || markBlock.getUrlTitle().isEmpty()) {
            width = (int) paint.measureText(text.toString()) + rect.right;
        } else {
            width = (int) paint.measureText(markBlock.getUrlTitle()) + rect.right;
        }
        if (fontMetricsInt != null) {
            //mutilLine(paint, fontMetricsInt, width);
            //单行居中显示
            Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
            int fontHeight = fmPaint.descent - fmPaint.ascent;
            int drHeight = rect.bottom - rect.top;
            int centerY = fmPaint.ascent + fontHeight / 2;

            fontMetricsInt.ascent = centerY - drHeight / 2;
            fontMetricsInt.top = fontMetricsInt.ascent;
            fontMetricsInt.bottom = centerY + drHeight / 2;
            fontMetricsInt.descent = fontMetricsInt.bottom;
        }
        return width;
    }

    /***
     * 多行,产品暂时看了飞书觉得不要,先不去调整这代码
     * @param paint
     * @param fontMetricsInt
     * @param width
     */
    private void sizeMoreLine(@NotNull Paint paint, Paint.@NotNull FontMetricsInt fontMetricsInt, int width) {
        if (editText == null || editText.getMeasuredWidth() == 0) {
            return;
        }
        //这里是为了改变高度问题
        Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
        //java.lang.ArithmeticException: divide by zero
        int i = width / (editText.getMeasuredWidth() != 0 ? editText.getMeasuredWidth() : width) + 1;//标识有多少行
        int fontHeight = (fmPaint.descent - fmPaint.ascent) * i + sp2px(editText.getContext(), 2) * i;
//            int drHeight = rect.bottom - rect.top;
        int drHeight = fontHeight;
        int centerY = fmPaint.ascent + fontHeight / 2;

        fontMetricsInt.ascent = centerY - drHeight / 2;
        fontMetricsInt.top = fontMetricsInt.ascent;
        fontMetricsInt.bottom = centerY + drHeight / 2;
        fontMetricsInt.descent = fontMetricsInt.bottom;
    }

    @Override
    public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
        Drawable drawable = chatMsgLinkDrawable;
        Rect rect = drawable.getBounds();
        text = text.subSequence(start, end);
        drawIcon(canvas, x, y, paint, drawable);
        paint.setColor(color);
        //drawMoreText(canvas, text, x, y, paint, rect);
        drawText(canvas, text, x, y, paint, rect);
    }

    private void drawIcon(@NotNull Canvas canvas, float x, int y, @NotNull Paint paint, Drawable drawable) {
        //这里画图片
        canvas.save();

        Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
        int fontHeight = fmPaint.descent - fmPaint.ascent;
        int centerY = y + fmPaint.descent - fontHeight / 2;
        int transY = centerY - (drawable.getBounds().bottom - drawable.getBounds().top) / 2;
        //这是多行居中代码,不过还有点bug
        //int transY = drawMoreLine(y, drawable, width, fmPaint);
        //居中
        canvas.translate(x, transY);
        drawable.draw(canvas);
        canvas.restore();
    }

    private int drawMoreLine(int y, Drawable drawable, int width, Paint.FontMetricsInt fmPaint) {
        if (editText == null || editText.getMeasuredWidth() == 0) {
            return 0;
        }
        int i = width / editText.getWidth() + 1;//标识有多少行
        int fontHeight = fmPaint.descent - fmPaint.ascent;
        int centerY = y + fmPaint.descent - fontHeight / 2;
        int transY = centerY - (drawable.getBounds().bottom - drawable.getBounds().top) / 2;
        return transY;
    }

    private void drawText(@NotNull Canvas canvas, CharSequence text, float x, int y, @NotNull Paint paint, Rect rect) {
        if (markBlock.getUrlTitle() == null || markBlock.getUrlTitle().isEmpty()) {
            canvas.drawText(text.toString(), x + rect.right, y, paint);
        } else {
            canvas.drawText(markBlock.getUrlTitle(), x + rect.right, y, paint);
        }
    }

    private void drawMoreText(@NotNull Canvas canvas, CharSequence text, float x, int y, @NotNull Paint paint, Rect rect) {
        //这里画文字
        canvas.save();
        //这里修改textPaint
        textPaint.setTextSize(paint.getTextSize());
        textPaint.setColor(color);
        //平移对于位置
        canvas.translate(x + rect.right, y);
        StaticLayout staticLayout;
        if (markBlock.getUrlTitle() == null || markBlock.getUrlTitle().isEmpty()) {
            //canvas.drawText(text.toString(), x + rect.right, y, paint);
            staticLayout = new StaticLayout(text.toString(), textPaint, canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
        } else {
            //canvas.drawText(markBlock.getUrlTitle(), x + rect.right, y, paint);
            staticLayout = new StaticLayout(markBlock.getUrlTitle(), textPaint, canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
        }
        staticLayout.draw(canvas);
        canvas.restore();
    }


    /**
     * 将sp值转换为px值,保证文字大小不变
     *
     * @param spValue (DisplayMetrics类中属性scaledDensity)
     * @return
     */
    public static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }

}

不方便发自己app,只能发下飞书输入框效果

在列表,就需要另外一个方案处理,还没处理完待续

 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/992794.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存