Android開(kāi)發(fā)——自定義準(zhǔn)備工作以及繪制

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)容

  1. Bitmap 圖片
  2. Canvas 繪制類->可以理解成一塊畫(huà)板
    ????提供了各種繪制方法
  3. Paint 畫(huà)筆->設(shè)置畫(huà)筆的樣式
  4. 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ù)


    貝塞爾圖解.png

繪制曲線可以設(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ú)立的


arcTo.png

drawArc.png

可以看到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)的效果


    useCenter.png

可以根據(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)控制四角的弧度


roundRect.png
rx圖解.png

小結(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)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末示罗,一起剝皮案震驚了整個(gè)濱河市惩猫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蚜点,老刑警劉巖轧房,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異绍绘,居然都是意外死亡奶镶,警方通過(guò)查閱死者的電腦和手機(jī)迟赃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)厂镇,“玉大人纤壁,你說(shuō)我怎么就攤上這事∞嘈牛” “怎么了酌媒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)迄靠。 經(jīng)常有香客問(wèn)我秒咨,道長(zhǎng),這世上最難降的妖魔是什么掌挚? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任雨席,我火速辦了婚禮,結(jié)果婚禮上吠式,老公的妹妹穿的比我還像新娘陡厘。我一直安慰自己,他們只是感情好特占,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布雏亚。 她就那樣靜靜地躺著,像睡著了一般摩钙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上查辩,一...
    開(kāi)封第一講書(shū)人閱讀 49,929評(píng)論 1 290
  • 那天胖笛,我揣著相機(jī)與錄音,去河邊找鬼宜岛。 笑死长踊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萍倡。 我是一名探鬼主播身弊,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼列敲!你這毒婦竟也來(lái)了阱佛?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤戴而,失蹤者是張志新(化名)和其女友劉穎凑术,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體所意,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡淮逊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年催首,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泄鹏。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡郎任,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出备籽,到底是詐尸還是另有隱情舶治,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布胶台,位于F島的核電站歼疮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏诈唬。R本人自食惡果不足惜韩脏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铸磅。 院中可真熱鬧赡矢,春花似錦、人聲如沸阅仔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)八酒。三九已至空民,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間羞迷,已是汗流浹背界轩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衔瓮,地道東北人浊猾。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像热鞍,于是被迫代替她去往敵國(guó)和親葫慎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350