Android Custom View 102 (Part 15)

Draw circled avatar

Guowei Lv

1 minute read

Let’s use Xfermode to draw a circled avatar.

The original avatar image is this:

Original Avatar Image

We will implement a custom view that clips it into a circle.

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

    private val WIDTH = dp2px(300)

    private val PADDING = dp2px(50)

    val paint = Paint(Paint.ANTI_ALIAS_FLAG)

    val bitmap = getAvatar(WIDTH.toInt())

    val xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)

    val savedArea = RectF()

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        savedArea.set(
            PADDING,
            PADDING,
            PADDING + WIDTH,
            PADDING + WIDTH
        )
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        val saved = canvas.saveLayer(savedArea, paint)
        canvas.drawOval(PADDING, PADDING, PADDING + WIDTH, PADDING + WIDTH, paint)
        paint.xfermode = xfermode
        canvas.drawBitmap(bitmap, dp2px(50), dp2px(50), paint)
        paint.xfermode = null
        canvas.restoreToCount(saved)
    }
    
    private fun getAvatar(width: Int): Bitmap {
        val options: BitmapFactory.Options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeResource(resources, R.drawable.avatar, options)
        options.inJustDecodeBounds = false
        options.inDensity = options.outWidth
        options.inTargetDensity = width
        return BitmapFactory.decodeResource(resources, R.drawable.avatar, options)
    }
}

Avatar Circled

For detailed explanation of Xfermode, please refer to this post

comments powered by Disqus