2020.8.20
一.引言
自定義控件分為自定義View和ViewGroup兩種最楷,一個(gè)控件的創(chuàng)建都會(huì)經(jīng)歷onMeasure揽咕、onLayout腹泌、onDraw三個(gè)階段,但View和ViewGroup各有特色
- 自定義View
1.onMeasure
2.onDraw - 自定義ViewGroup
1.onMeasure
2.onLayout
對(duì)于View言询,不需要重寫(xiě)onLayout方法俯萎,ViewGroup不需要重寫(xiě)onDraw
二.以自定義View為例重寫(xiě)構(gòu)造方法
此處以自定義View為例,首先我們需要?jiǎng)?chuàng)建一個(gè)類倍试,讓它繼承View讯屈,并添加構(gòu)造方法,通常添加一下三種構(gòu)造方法
class testView:View {
//在代碼中創(chuàng)建
constructor(context: Context):super(context){}
//在xml中創(chuàng)建
constructor(context: Context,attr: AttributeSet):super(context,attr){}
//需要使用到style
constructor(context: Context,attr: AttributeSet,style:Int):super(context,attr,style){}
}
三.重寫(xiě)onDraw進(jìn)行繪制主體內(nèi)容
按照流程县习,應(yīng)先重寫(xiě)onMeasure方法,但本片文章主要介紹自定義繪制谆趾,onMeasure將在另外一篇文章中詳寫(xiě)
繪畫(huà)的4個(gè)基礎(chǔ)內(nèi)容
- Bitmap 圖片
- Canvas 繪制類->可以理解成一塊畫(huà)板
????提供了各種繪制方法 - Paint 畫(huà)筆->設(shè)置畫(huà)筆的樣式
- Path 用于設(shè)置繪制的路徑
1.繪制背景顏色
override fun onDraw(canvas: Canvas?) {
setBackgroundColor(Color.MAGENTA)
}
除了使用系統(tǒng)提供的顏色外躁愿,還可以使用自己手動(dòng)創(chuàng)建的顏色
通過(guò)Color.parseColor("#B990E7")來(lái)實(shí)現(xiàn)
具體使用實(shí)例:setBackgroundColor(Color.parseColor("#B990E7"))
2.畫(huà)圓
drawCircle(圓心x,圓心y,raduis,paint)
需要提前準(zhǔn)備好圓心坐標(biāo)以及半徑和畫(huà)筆
注:onDraw方法會(huì)被多次調(diào)用,所以盡量不要在這個(gè)方法里面創(chuàng)建對(duì)象(變量)沪蓬,最好設(shè)置為屬性
- onSizeChanged()->此方法是在onMeasure之后調(diào)用彤钟,也就是說(shuō),我們可以在此獲取控件的寬高跷叉,這點(diǎn)很重要逸雹,比如我們需要繪制一個(gè)圖形,該圖形的大小以空間的寬高為參考云挟,所以我們?cè)诖朔椒ㄖ袑?duì)圖形繪制所需要的尺寸進(jìn)行賦值
var cx = 0f
var cy = 0f
var radius = 0f
var mWidth = 0
var mHeight = 0
val mPaint = Paint().apply {
color = Color.MAGENTA
style = Paint.Style.STROKE
strokeWidth=3f
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
mWidth = measuredWidth
mHeight = measuredHeight
//獲取半徑大小
radius = if (mWidth>mHeight) mHeight/2f else mWidth/2f
//設(shè)置圓心
cx = mWidth/2f
cy = mHeight/2f
}
override fun onDraw(canvas: Canvas?) {
canvas?.drawCircle(cx,cy,radius,mPaint)
}
- 畫(huà)筆-Paint
color 設(shè)置顏色
style 設(shè)置填充方式
???Paint.Style.STROKE 描邊
???Paint.Style.FILL 全填充
???Paint.Style.FILL_AND_STROKE 填充+描邊
strokeWidth 設(shè)置畫(huà)筆粗細(xì)(float類型) - 設(shè)置畫(huà)筆顏色
1.除了使用系統(tǒng)提供的和前面寫(xiě)到的Color.parseColor("#B990E7")來(lái)設(shè)置顏色外梆砸,還可以使用setARGB()來(lái)設(shè)置,四個(gè)參數(shù)园欣,A代表透明度(255不透明帖世,0全透明),RGB即對(duì)應(yīng)了紅綠藍(lán)三原色的深度沸枯,范圍都是0-255
setARGB(100,175,202,253)
2.著色器shader
子類1:LinearGradient-線性漸變
???起始點(diǎn)(x0,y0)日矫,終點(diǎn)(x1,y1),color0-color1漸變色
???tile:Shader.TileMode->CLAMP 邊緣色拉伸
?????????????REPEAT 重復(fù)
?????????????MIRROR 倒影
子類2:BitmapShader-用一張圖片作為顏色進(jìn)行繪制
子類3:RadialGradient-發(fā)射式
子類3:SweepGradient-掃射式
使用示例
shader=LinearGradient(
mWidth/2f,0f,mWidth/2f,mHeight.toFloat(),
Color.GREEN,Color.MAGENTA,Shader.TileMode.CLAMP
)
----------------------------------------------------------------------------------------
val img = BitmapFactory.decodeResource(resources,R.drawable.wiwi)
shader=BitmapShader(img,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP)
小貼士:將畫(huà)筆顏色設(shè)置為圖片搭配畫(huà)圓可以實(shí)現(xiàn)圓形頭像
3.drawBitmap
將一張圖片繪制到控件中绑榴,這和上面的畫(huà)筆以圖片為顏色是不相同的哪轿,畫(huà)筆以圖片為顏色繪制是平鋪的,不可設(shè)置位置翔怎,不夠靈活窃诉,并且依賴于你選擇繪制的形狀杨耙,而drawBitmap是獨(dú)立的元素將圖片添加到控件中,各有各的好處
private val pic:Bitmap by lazy {
BitmapFactory.decodeResource(resources,R.drawable.alipay)
}
canvas?.drawBitmap(pic,0f,0f,mPaint)
通過(guò)設(shè)置左邊和上邊與控件的距離來(lái)控制繪制的區(qū)域
4.drawPath與drawLine
畫(huà)一條線只需要起點(diǎn)和終點(diǎn)的坐標(biāo)即可
drawLine(startX,startY,endX,endY,paint)褐奴,但如果需要連續(xù)畫(huà)線的話按脚,drawLine就顯得太笨拙了,讓代碼更加冗雜敦冬,此時(shí)就需要用到drawPath
- drawPath(path,paint)
繪制路徑只需要設(shè)置path辅搬,并且path還可動(dòng)態(tài)修改 - Path() 路徑
moveTo(x,y) 移動(dòng)到某一點(diǎn),并作為下一條線的起點(diǎn)
lineTo(x,y) 畫(huà)到某點(diǎn)脖旱,作為終點(diǎn)
5.繪制貝塞爾曲線
drawPath不僅可以畫(huà)直線堪遂,還可畫(huà)曲線,只需要設(shè)置路徑即可
- quadTo(x1,y1,x2,y2)
(x1,y1)為控制點(diǎn)萌庆,(x2,y2)是終點(diǎn)溶褪,這是2階貝塞爾,該方法同moveTo一樣在path內(nèi)部設(shè)置 -
cubicTo(x1,y1,x2,y2,x3,y3)
中間過(guò)程多一個(gè)控制點(diǎn)的坐標(biāo)践险,就會(huì)多一個(gè)階數(shù)
繪制曲線可以設(shè)計(jì)出很多新奇的圖案猿妈,只需計(jì)算好控制點(diǎn)的坐標(biāo)即可
6.畫(huà)圓弧
畫(huà)圓弧有兩種方式,一是使用path路徑中的arcTo巍虫,二是drawArc()
兩者都需要確定繪制圓弧的矩形區(qū)域以及掃過(guò)的角度(圓弧對(duì)應(yīng)的角度)
不同之處彭则,arcTo在path內(nèi)部,不需要設(shè)置畫(huà)筆占遥,圓心的確定使用moveTo俯抖,因此arcTo依賴于drawPath,而drawArc是獨(dú)立的
可以看到drawArc畫(huà)出來(lái)的效果更好瓦胎,繪制圓弧有個(gè)前提芬萍,你給出的區(qū)域必須是一個(gè)正方形區(qū)域rect
- arcTo
val path = Path().apply {
moveTo(500f,400f)
val rect = RectF(100f,10f,900f,800f)
arcTo(rect,0f,-90f)
}
-
drawArc(left,top,right,bottom,startAngle,sweepAngle,是否使用中心點(diǎn),paint)
下圖是使用中心點(diǎn)的效果
可以根據(jù)自己的需求來(lái)設(shè)置是否使用中心點(diǎn)
同理畫(huà)圓也可以通過(guò)path路徑來(lái)設(shè)置
- addCircle(x,y,radius,方向)
CW 順時(shí)針
CCW 逆時(shí)針
addCircle(600f,400f,100f,Path.Direction.CW)
7.畫(huà)圓角矩形
為了給后面的小Demo做鋪墊,這里介紹一下繪制圓角矩形
drawRoundRect(left,top,right,bottom,rx,ry)
這里重點(diǎn)說(shuō)明rx,ry兩個(gè)參數(shù)搔啊,它們是用來(lái)控制四角的弧度
小結(jié):基本的繪制如上文所示柬祠,自定義動(dòng)畫(huà)是建立在自定義控件的基礎(chǔ)上的,可以說(shuō)自定義控件就是用來(lái)自定義動(dòng)畫(huà)坯癣,手動(dòng)實(shí)現(xiàn)系統(tǒng)沒(méi)有的控件以及動(dòng)畫(huà)效果瓶盛,所以接下來(lái)會(huì)將兩者融合詳講,并以項(xiàng)目來(lái)鞏固知識(shí)點(diǎn)