Draw text inside a filled rectangle using Canvas Android
Asked Answered
C

3

5

How to draw a filled rectangle with specified bounds and inside that rectangle text to be drawn using Canvas Android ?? I tried

mPaint.setColor(Color.GREEN);
canvas.drawText(mText, x, y, mPaint);
mPaint.setColor(Color.BLACK);
canvas.drawRect(x, y, x + w, y + h, mPaint);

but text is not inside of that rectangle. Can any buddy tell me how to draw a rectangle surrounding specified text with consideration of text size ??

Clipboard answered 25/3, 2013 at 7:5 Comment(0)
A
13

Here i have hardcoded x and y values. You can change them

        mpaint= new Paint();
        mpaint.setColor(Color.RED);
        mpaint.setStyle(Style.FILL);
        paint2= new Paint();
        paint2.setColor(Color.GREEN);
        paint2.setTextSize(50);  //set text size
        float w = paint2.measureText(s)/2;
        float textSize = paint2.getTextSize();


        @Override
        protected void onDraw(Canvas canvas) {
            paint2.setTextAlign(Paint.Align.CENTER);
            canvas.drawRect(300-w, 300 - textsize, 300 + w, 300, mpaint);
            canvas.drawText(s, 300, 300 ,paint2); //x=300,y=300    
        }

Edit :

Its bad a idea to call measureText in onDraw. You can do that outside of onDraw.

There is a video on also about performance and why you should avoid allocations in onDraw. https://www.youtube.com/watch?v=HAK5acHQ53E

Resulting snap shot

enter image description here

Appraisal answered 25/3, 2013 at 7:25 Comment(9)
Sorry forgot to mention, the rectangle should cover only text area and the position and text size may change dynamically. Depends on the text size and length i 've to draw rectangle ??Clipboard
Why is there an empty space in the drawn rectangle? drawtext by default uses some top padding, if yes how to avoid that?Finkelstein
@AlexanderFarber it must be copy paste mistake. I copied the code from the editor. I forgot and take that out.Appraisal
@Finkelstein you can always play with the values. left , right ,top and bottom to get it right. this is just a sampleAppraisal
Still bad solution to call measureText() in onDraw(), twice.Democratize
@AlexanderFarber agree i answered this long back and i will rectify this soon.Appraisal
@AlexanderFarber edited and post a link that also explains why we should avoid allocations in onDraw and thanks for pointing out the mistake.Appraisal
What if textsize is greater than 300??, In this case text gets cut from left.Duleba
@Duleba measure the text height and width and then draw the rect #3654821Appraisal
M
6

If you have to center the text inside de rect you have use this code

    mpaint= new Paint();
    mpaint.setColor(Color.RED);
    mpaint.setStyle(Style.FILL);
    paint2= new Paint();
    paint2.setColor(Color.GREEN);
    paint2.setTextSize(50);  //set text size
    float w = paint2.measureText(s)/2;
    float textSize = paint2.getTextSize();


    @Override
    protected void onDraw(Canvas canvas) {
        paint2.setTextAlign(Paint.Align.CENTER);
        Rect rect = new Rect(300-w, 300 - textsize, 300 + w, 300);
        canvas.drawRect(rect, mpaint);
        canvas.drawText(s, rect.centerX(), rect.centerY() ,paint2); // center text inside rect
    }

enter image description here

Miquelon answered 24/10, 2019 at 14:23 Comment(0)
E
0

This might be very late for this particular query but I think many will find this answer useful. So, the problem with the Canvas for any CustomView is that, you can get the width for a particular text, but it's not that easy to get the height of the text. Also if you are using canvas.drawText(....) with simple Paint object, you can not draw multi line text. So, use the below code within your onDraw() method.

String displayText = "Hello World";
int mainTextPositionX = getWidth() / 2 ;
int mainTextPositionY = getHeight() / 2;

StaticLayout textStaticLayout;
TextPaint textPaint;
textPaint = new TextPaint();
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setColor(Color.BLUE);
textPaint.setAntiAlias(true);
textPaint.setTextSize(convertDpToPixel(30, context));
textPaint.setTextAlign(Paint.Align.CENTER);
highlightedRectPaint = new Paint();

highlightedRectPaint.setStrokeWidth(12);
highlightedRectPaint.setStyle(Paint.Style.STROKE);
highlightedRectPaint.setColor(Color.RED);
highlightedRectPaint.setAntiAlias(true);

if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        textStaticLayout = StaticLayout
                .Builder
                .obtain(displayText, 0, displayText.length(), textPaint, (int) textPaint.measureText(displayText))
                .build();
    }else{
        textStaticLayout = new StaticLayout(
                displayText, textPaint, (int)textPaint.measureText(displayText), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
    }

    Rect highlightedTextBorderRect = new Rect();
    highlightedTextBorderRect.top = mainTextPositionY-20;
    highlightedTextBorderRect.left = mainTextPositionX- 
    ((int)textPaint.measureText(displayText)/2)-20;
    highlightedTextBorderRect.right = mainTextPositionX+ 
    ((int)textPaint.measureText(displayText)/2) + 20;
    highlightedTextBorderRect.bottom = mainTextPositionY+ 
    (int)textStaticLayout.getHeight()+20;

    canvas.save();
    canvas.translate(mainTextPositionX, mainTextPositionY);
    textStaticLayout.draw(canvas);
    canvas.restore();

    canvas.drawRect(highlightedTextBorderRect,highlightedRectPaint);

just make sure that, you declare all the objects and variable outside of the draw() method. And this will draw a rectangle outline around the text with multi line support. If you want the rectangle to have a fill, then just use the highlightedRectPaint and change the setStyle(Paint.Style.FILL). Hope that helps.

Eyas answered 17/11, 2018 at 2:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.