简体   繁体   中英

How to draw arc with starting text

I have to create an arc using canvas and add text in the start position of arc, but it does not look proper. Please see the image my text is cut off the top position, My text display linear not curve.

在此处输入图片说明

My Code

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (mRect == null) {
            centerX = getMeasuredWidth() / 2;
            centerY = getMeasuredHeight() / 2;
            radius = Math.min(centerX, centerY);
            int startTop = STROKE_WIDTH / 2;
            mRect = new RectF(STROKE_WIDTH / 2, STROKE_WIDTH / 2, (2 * radius - startTop), (2 * radius - startTop));
            canvas.drawArc(mRect, 270, 270, false, mDegreesPaint);

            Paint paint = new Paint();

            paint.setColor(Color.TRANSPARENT);
            paint.setAntiAlias(true);
            paint.setStyle(Paint.Style.FILL_AND_STROKE);
            paint.setTextAlign(Paint.Align.LEFT);
            paint.setLinearText(true);
            canvas.drawPaint(paint);

            paint.setColor(getResources().getColor(R.color.colorPrimaryDark));
            paint.setTextSize(30);

            //float radius = 300;
                float x = (float)(radius * Math.cos(mRect.width() * Math.PI)) + getWidth()/2 - 10;
                float y = (float)(radius * Math.sin(mRect.height() * Math.PI )) + getHeight()/2 - 20;

            Path addArc = new Path();
            addArc.arcTo(mRect, 250, 270);

            canvas.drawTextOnPath("text",addArc, 0, 0 , paint);




        }
    }

Look at this method:

public void drawTextOnPath (String text, 
                Path path, 
                float hOffset, 
                float vOffset, 
                Paint paint)

Here, vOffset (float) is the distance above(-) or below(+) the path to position the text.

And, hOffset (float) is the distance along the path to add to the text's starting position.

Try changing values in vOffset and hOffset to position text according to the requirement.

Adjusting Arc thickness and text size:

Either use this method paint.setStrokeWidth(x); to increase your arc thickness or decrease the size of text in this paint.setTextSize(30); .

That if (mRect == null) line is going to mess you up if the view gets redrawn. It will turn blank. You should instantiate the Rectangle at its declaration and modify its dimensions in onDraw(). I would also set up your paint outside your draw method to make it faster if this view has to get redrawn in an animation.

I'm not sure what the x and y are for in your code, but whatever you were calculating most likely doesn't make sense since you have the height and width inside the trig functions.

So you got the arc to draw inside the rectangle by subtracting half its stroke width. Then you use this same rectangle to make the arc for the text to sit on. Text is drawn at its baseline (the bottom of letters that don't hang down like g, j, p, and y).

So in your case, you probably want the text to fit inside the view bounds, so you should make an arc that is smaller than the view by the size of your text instead of half the stroke width that you used for your arc.

I also see an error in how you place your rectangle for the circular arc. It is located via bottom left corner of the view. So if you view is not square, it will be off center. You should located based on the center point.

Since you do this calculation twice, you can write a function for it.

private val mRect = RectF()
private val mTextPaint = Paint().apply {
    color = resources.getColor(R.color.colorPrimaryDark)
    antiAlias = true
    style = Paint.Style.FILL_AND_STROKE
    textAlign = Paint.Align.LEFT
    linearText = true
}

private fun updateCenteredRect(rect: RectF, inset: Int) {
    val centerX = measuredWidth / 2
    val centerY = measuredHeight / 2
    val radius = min(centerX, centerY) - inset
    rect.set(centerX - radius, centerY - radius, radius * 2, radius * 2)
}

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    updateCenteredRect(mRect, STROKE_WIDTH / 2)
    canvas.drawArc(mRect, 270, 270, false, mDegreesPaint)

    val textSize = 30 // You should calculate this based on screen density or it will look too big or small on some devices
    mTextPaint.textSize = textSize
    updateCenteredRect(mRect, textSize)
    Path addArc = new Path().apply {
        arcTo(mRect, 250, 270)
    }
    canvas.drawTextOnPath("text", addArc, 0, 0, mTextPaint)
}

I wrote this without really noticing your original code is in Java. I found your question through the Kotlin tag.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM