Android自定義View(18) 《多種實(shí)現(xiàn)圓形頭像的方法》

概述

寫自定義View也有一陣了,買的書基本上也看的差不多了,今天就抽空整理一下實(shí)現(xiàn)圓形頭像的方法,順便也回顧一下之前的知識(shí)點(diǎn)~

目標(biāo)

在日常的開發(fā)中我們會(huì)對(duì)圖像進(jìn)行多種處理,有可能是圓形,也可能是邊框帶圓弧的形狀,雖然形狀不一,但是我們實(shí)現(xiàn)的思路是一樣的,那么今天就拿圓形頭像來舉例說明了,其他圖形應(yīng)該也很容易舉一反三了,我們現(xiàn)在的目標(biāo),就是要得到如下一個(gè)圓形頭像

頭像結(jié)果

circleImageView.png

準(zhǔn)備工作

一般繪制時(shí)我們都是需要知道控件的大小的,這里我們就需要獲得中心點(diǎn)的x,y坐標(biāo)和半徑的大小,以及圖片數(shù)據(jù)

    private var centerX = 0f
    private var centerY = 0f
    private var radius = 0f
    private var bitmap : Bitmap = BitmapFactory.decodeResource(resources, R.drawable.avatar)
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        centerX = (w/2).toFloat()
        centerY = (h/2).toFloat()
        radius = (w/2).toFloat()
        bitmap = Bitmap.createScaledBitmap(bitmap,w,height,false)
        setLayerType(LAYER_TYPE_SOFTWARE,null)
    }

多種實(shí)現(xiàn)方式

1.切割畫布

這個(gè)方法主要是以下步驟

    1. 先保存Canvas的狀態(tài)
    1. 然后將Canvas切割成一個(gè)圓形
    1. 在這個(gè)Canvas上繪制圖像
    1. 最后再恢復(fù)畫布狀態(tài)。(因?yàn)閏lip函數(shù)是不可逆的,一定要先保存狀態(tài))
    private fun byClipCanvas(canvas: Canvas){
        var matrix = Matrix()
        var saveId = canvas.save()
        var path = Path()
        path.addCircle(centerX,centerY,radius,Path.Direction.CW)
        canvas.clipPath(path)
        canvas.drawBitmap(bitmap,matrix,null)
        canvas.restoreToCount(saveId)
    }

2.利用BitmapShader

這種方式相對(duì)來說比較簡單,步驟如下

  • 1.創(chuàng)建一個(gè)bitmapShader
  • 2.將其設(shè)置給畫筆
  • 3.畫筆繪制出對(duì)應(yīng)的圓形區(qū)域即可
 private fun byBitmapShader(canvas: Canvas){
        var paint = Paint()
        var bitmapShader = BitmapShader(bitmap,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP)
        paint.shader = bitmapShader
        canvas.drawCircle(centerX,centerY,radius,paint)
    }

3.利用PorterDuffXfermode混合模式來進(jìn)行繪制

這種方式我們主要利用PorterDuff.Mode.SRC_IN這個(gè)模式的特性,首先我們看這個(gè)模式的計(jì)算公式

         * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
         * <p>\(C_{out} = C_{src} * \alpha_{dst}\)</p>

由此我們可見,當(dāng)dst的alpha值為0時(shí),最終輸出的alpha值也為0,那么在頭像圖片是不透明的情況下,我們可以采用這樣的方式

  • 1.先繪制一個(gè)圓,paint的默認(rèn)顏色為Black,所以可以不用特別設(shè)置顏色
  • 2.給Paint設(shè)置PorterDuff.Mode.SRC_IN模式
  • 3.繪制頭像
private fun byPorterDufferModeCanvas(canvas: Canvas) {
        var paint = Paint()
        canvas.drawCircle(centerX, centerY, radius, paint)
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(bitmap, Matrix(), paint)
        paint.xfermode = null
    }

4.利用ShapeDrawable

ShapeDrawable的構(gòu)造方法中,有一個(gè)是OvalShape,顧名思義就是一個(gè)橢圓形的drawable,那么我們就可以這樣做

  • 1.創(chuàng)建一個(gè)圓形的shapeDrawable
  • 2.給shapeDrawable的paint設(shè)置BitmapShader
  • 3.然后將shapeDrawable繪制在canvas上
private fun byOvalDrawable(canvas: Canvas) {
        var ovalShapeDrawable = ShapeDrawable(OvalShape())
        // ovalShapeDrawable 在控件中的位置 
        ovalShapeDrawable.setBounds(
            (centerX - radius).toInt(),
            (centerY - radius).toInt(), (centerX + radius).toInt(), (centerY + radius).toInt()
        )
        ovalShapeDrawable.paint.shader =
            BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        ovalShapeDrawable.draw(canvas)
    }

注意點(diǎn)

在繪制的過程中一定要記得bitmap的大小縮放問題,因?yàn)榭丶膶捀吆蚥itmap的寬高是兩碼事,在使用bitmapShader的時(shí)候尤其要注意,它并不會(huì)對(duì)bitmap進(jìn)行縮放,而且是從左上角開始繪制

總結(jié)

圓形頭像的實(shí)現(xiàn)只是其中一種用途,我們還可以使用上述的幾種方式來實(shí)現(xiàn)各種形狀圖片的繪制~今天就到這吧,改天再想想下一篇寫點(diǎn)啥...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容