Android Spannablecontent With Rounded Corners

前端 未结 8 877
无人及你
无人及你 2020-12-13 15:06

I am trying to change my string to make a badge with a number in the middle by using Spannable String. I can highlight the appropriate letter/number by setting the BackGrou

8条回答
  •  借酒劲吻你
    2020-12-13 15:36

    Actually i found big issues with all of those answers when displaying multiple lines of badges. After lots of testing and tweaking. I Finally got the best version of the above.

    The basic idea is to trick the TextView by setting a much bigger text size and setting the wanted size inside the span. Also, you can see i'm drawing the badge background and text differently.

    So, this is my RoundedBackgroundSpan:

    public class RoundedBackgroundSpan extends ReplacementSpan {
    
        private static final int CORNER_RADIUS = 12;
    
        private static final float PADDING_X = GeneralUtils.convertDpToPx(12);
        private static final float PADDING_Y = GeneralUtils.convertDpToPx(2);
    
        private static final float MAGIC_NUMBER = GeneralUtils.convertDpToPx(2);
    
        private int mBackgroundColor;
        private int mTextColor;
        private float mTextSize;
    
        /**
         * @param backgroundColor color value, not res id
         * @param textSize        in pixels
         */
        public RoundedBackgroundSpan(int backgroundColor, int textColor, float textSize) {
            mBackgroundColor = backgroundColor;
            mTextColor = textColor;
            mTextSize = textSize;
        }
    
        @Override
        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
            paint = new Paint(paint); // make a copy for not editing the referenced paint
    
            paint.setTextSize(mTextSize);
    
            // Draw the rounded background
            paint.setColor(mBackgroundColor);
            float textHeightWrapping = GeneralUtils.convertDpToPx(4);
            float tagBottom = top + textHeightWrapping + PADDING_Y + mTextSize + PADDING_Y + textHeightWrapping;
            float tagRight = x + getTagWidth(text, start, end, paint);
            RectF rect = new RectF(x, top, tagRight, tagBottom);
            canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, paint);
    
            // Draw the text
            paint.setColor(mTextColor);
            canvas.drawText(text, start, end, x + PADDING_X, tagBottom - PADDING_Y - textHeightWrapping - MAGIC_NUMBER, paint);
        }
    
        private int getTagWidth(CharSequence text, int start, int end, Paint paint) {
            return Math.round(PADDING_X + paint.measureText(text.subSequence(start, end).toString()) + PADDING_X);
        }
    
        @Override
        public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
            paint = new Paint(paint); // make a copy for not editing the referenced paint
            paint.setTextSize(mTextSize);
            return getTagWidth(text, start, end, paint);
        }
    }
    

    And here is how i'm using it:

    public void setTags(ArrayList tags) {
        if (tags == null) {
            return;
        }
    
        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 26); // Tricking the text view for getting a bigger line height
    
        SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
    
        String between = " ";
        int tagStart = 0;
    
        float textSize = 13 * getResources().getDisplayMetrics().scaledDensity; // sp to px
    
        for (String tag : tags) {
            // Append tag and space after
            stringBuilder.append(tag);
            stringBuilder.append(between);
    
            // Set span for tag
            RoundedBackgroundSpan tagSpan = new RoundedBackgroundSpan(bgColor, textColor, textSize);
            stringBuilder.setSpan(tagSpan, tagStart, tagStart + tag.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    
            // Update to next tag start
            tagStart += tag.length() + between.length();
        }
    
        mTextView.setText(stringBuilder);
    }
    


    Note:

    • You can play with all sizes and constants to fit to your wanted style
    • If you use an external font be sure to set android:includeFontPadding="false" otherwise it can mess up the line's height

    Enjoy :)

提交回复
热议问题