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 ??

Arjun Kanti
  • 101
  • 2
  • 4
  • 12

3 Answers3

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

Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • 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 ?? – Arjun Kanti Mar 25 '13 at 07:39
  • Why is there an empty space in the drawn rectangle? drawtext by default uses some top padding, if yes how to avoid that? – vikki_logs Jul 24 '15 at 15:45
  • @AlexanderFarber it must be copy paste mistake. I copied the code from the editor. I forgot and take that out. – Raghunandan Sep 14 '15 at 03:19
  • @vikki_logs you can always play with the values. left , right ,top and bottom to get it right. this is just a sample – Raghunandan Sep 14 '15 at 03:27
  • 1
    Still bad solution to call `measureText()` in `onDraw()`, twice. – Alexander Farber Sep 14 '15 at 06:45
  • 1
    @AlexanderFarber agree i answered this long back and i will rectify this soon. – Raghunandan Sep 14 '15 at 06:46
  • @AlexanderFarber edited and post a link that also explains why we should avoid allocations in onDraw and thanks for pointing out the mistake. – Raghunandan Sep 14 '15 at 06:57
  • What if textsize is greater than 300??, In this case text gets cut from left. – Nainal Dec 08 '17 at 07:57
  • @Nainal measure the text height and width and then draw the rect https://stackoverflow.com/questions/3654321/measuring-text-height-to-be-drawn-on-canvas-android – Raghunandan Dec 08 '17 at 08:21
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

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.

androCoder-BD
  • 498
  • 7
  • 13