Ryan Lim
Ryan Lim

Reputation: 206

Android drawing semi circle with canvas

Can anyone help me out on how I going to draw semicircle of the picture below with canvas and also how to detect the collection of the drawing object?

Drawing Object

I had try to draw it using XML and i dont know how to detect the collision of it. I just want to detect the collision of the black part but not the whole circle. Thank you.

Upvotes: 4

Views: 7982

Answers (2)

Albert Vila Calvo
Albert Vila Calvo

Reputation: 15835

I've just done something similar, with a custom View:

class SemiCircleView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val paint: Paint = Paint()
    private var rectangle: RectF? = null
    private var margin: Float

    init {
        paint.isAntiAlias = true
        paint.color = ContextCompat.getColor(context, R.color.colorAquamarine)
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 5.dpToPx()
        margin = 3.dpToPx() // margin should be >= strokeWidth / 2 (otherwise the arc is cut)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (rectangle == null) {
            rectangle = RectF(0f + margin, 0f + margin, width.toFloat() - margin, height.toFloat() - margin)
        }
        canvas.drawArc(rectangle!!, 90f, 180f, false, paint)
    }

}

Add it you your XML layout like this:

<com.example.view.SemiCircleView
    android:layout_width="120dp"
    android:layout_height="120dp"/>

That's the result:

Android semi circle canvas setArc


In my case I want to programmatically control the % of the circle being drawn, so I've added a method setArcProportion that controls that:

class SemiCircleView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val mainPaint: Paint = Paint()
    private val backgroundPaint: Paint = Paint()
    private var rectangle: RectF? = null
    private var margin: Float
    private var arcProportion: Float = 0f

    init {
        mainPaint.isAntiAlias = true
        mainPaint.color = ContextCompat.getColor(context, R.color.colorLutea)
        mainPaint.style = Paint.Style.STROKE
        mainPaint.strokeWidth = 5.dpToPx()
        backgroundPaint.isAntiAlias = true
        backgroundPaint.color = ContextCompat.getColor(context, R.color.black_08)
        backgroundPaint.style = Paint.Style.STROKE
        backgroundPaint.strokeWidth = 5.dpToPx()
        margin = 3.dpToPx() // margin should be >= strokeWidth / 2 (otherwise the arc is cut)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (rectangle == null) {
            rectangle = RectF(0f + margin, 0f + margin, width.toFloat() - margin, height.toFloat() - margin)
        }
        canvas.drawArc(rectangle!!, -90f, arcProportion * 360, false, mainPaint)
        // This 2nd arc completes the circle. Remove it if you don't want it
        canvas.drawArc(rectangle!!, -90f + arcProportion * 360, (1 - arcProportion) * 360, false, backgroundPaint)
    }

    /**
     * @param arcProportion The proportion of the semi circle arc, from 0 to 1. Setting 0 makes the arc invisible, and 1
     * makes a whole circle.
     */
    fun setArcProportion(arcProportion: Float) {
        this.arcProportion = arcProportion
        invalidate()
    }

}

So if I do semiCircleView.setArcProportion(0.62f) I have:

Android semi circle canvas setArc

Bonus - To make the arc grow with an animation modify setArcProportion like this:

private const val ANIMATION_BASE_DURATION_MS: Long = 500 // milliseconds

fun setArcProportion(arcProportion: Float) {
    ValueAnimator.ofFloat(0f, arcProportion).apply {
        interpolator = DecelerateInterpolator()
        // The animation duration is longer for a larger arc
        duration = ANIMATION_BASE_DURATION_MS + (arcProportion * ANIMATION_BASE_DURATION_MS).toLong()
        addUpdateListener { animator ->
            [email protected] = animator.animatedValue as Float
            [email protected]()
        }
        start()
    }
}

Upvotes: 11

Damanpreet Singh
Damanpreet Singh

Reputation: 726

  1. In your onDraw method draw a circle .

    canvas.drawCircle(x, y, 10, paint);

  2. Now draw a rect with your background colour

    Paint fillBackgroundPaint = new Paint();
    fillBackgroundPaint.setAntiAlias(true);
    fillBackgroundPaint.setStyle(Paint.Style.FILL);
    canvas.drawRect(x,y+10,x+10,y-10);
    

This should serve the purpose.

Upvotes: -1

Related Questions