Search code examples
androidcanvaskotlinandroid-imageview

Android: Add quad bezier rounded corners to View


I want to have an ImageView containing an Image with rounded curves, but not circular (which is way easier of course)..

enter image description here

The X marked areas should be black, the rest should stay blue. It should look (kind of) like this

What I tried: I spent hours fighting with Path.quadTo and Path.cubicTo with the help of some tools but I didn't have any success yet. I just don't really get the usage to be honest.

What my code currently looks like:

override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val paint = Paint()
        paint.color = Color.BLACK
        paint.strokeWidth = 1f
        paint.strokeCap = Paint.Cap.ROUND
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)

        paint.style = Paint.Style.FILL

        val fHeight = canvas.height.toFloat()
        val startEndHeight = canvas.height / 1.18f
        val fWidth = canvas.width.toFloat()
        val halfWidth = (fWidth / 2)

        val path = Path()
        //X = Left side, Y = close to bottom
        val ptStart = PointF(0f, startEndHeight)
        //X = Middle, Y = Bottom
        val ptMiddle = PointF(halfWidth, fHeight + 95)
        // X = Right Side, Y = close to bottom
        val ptEnd = PointF(fWidth, startEndHeight)

        path.moveTo(ptStart.x, ptStart.y)
        path.quadTo(ptMiddle.x, ptMiddle.y, ptEnd.x, ptEnd.y)

        path.close()

        canvas.drawPath(path, paint)
    }

It can't be that hard, right? Is it possible to colorize the red marked areas and leave everything else untouched?


Solution

  • Fixed! This is my final solution which applies a quad bezier to the ImageView. I had to add 2 lines to the path to get the result I wanted.

    class HeaderImageView : AppCompatImageView {
        constructor(context: Context?) : super(context) {
            init()
        }
    
        constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
            init()
        }
    
        constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
            init()
        }
    
        lateinit var paint: Paint
    
        private fun init() {
            paint = Paint()
            paint.color = Color.WHITE
            paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)
            paint.style = Paint.Style.FILL
        }
    
        @SuppressLint("CanvasSize")
        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
    
            val fHeight = canvas.height.toFloat()
            val startEndHeight = canvas.height / 1.18f
            val fWidth = canvas.width.toFloat()
            val halfWidth = (fWidth / 2)
    
            val path = Path()
            //X = Left side, Y = close to bottom
            val ptStart = PointF(0f, startEndHeight)
            //X = Middle, Y = Bottom
            val ptMiddle = PointF(halfWidth, fHeight + 95)
            // X = Right Side, Y = close to bottom
            val ptEnd = PointF(fWidth, startEndHeight)
    
            path.moveTo(ptStart.x, ptStart.y)
            path.quadTo(ptMiddle.x, ptMiddle.y, ptEnd.x, ptEnd.y)
            path.lineTo(fWidth, fHeight)
            path.lineTo(0f, fHeight)
    
            path.close()
    
            canvas.drawPath(path, paint)
        }
    }
    

    enter image description here