需求分析
需要做成一個如圖的類似書簽tab欄。
實現(xiàn)思路
直接用selector替換背景肯定可以购披,但是想試試許久沒用的自定義控件杖挣。
繼承view,onMeasure獲得寬高刚陡,onDraw繪制背景惩妇,繪制選中顏色株汉,繪制文字「柩辏看起來十分簡單乔妈。
然而年輕的我還是太連清了。UI在左右兩邊分別加了一個圓角氓皱,這用路徑就很難畫了褒翰。
本來想用arcTo方法繪制
mPath.arcTo(ovalRectF, startAngle, sweepAngle) , ovalRectF為橢圓的矩形,startAngle 為開始角度匀泊,sweepAngle 為結(jié)束角度优训。
但通過嘗試發(fā)現(xiàn)圓弧的曲率很難計算,畫出來的圓弧角度很奇怪各聘,打算使用貝塞爾曲線揣非。
貝塞爾曲線不僅能畫直線,也能畫曲線躲因。即便是更復(fù)雜的曲線早敬,控制點的增加也只是線性的。這一特點使其不光在工業(yè)設(shè)計領(lǐng)域大展拳腳大脉,就連數(shù)學(xué)基礎(chǔ)不好的人也可以比較容易地掌握搞监,比如大多數(shù)平面美術(shù)設(shè)計師們。
簡單來說镰矿,貝塞爾曲線就是將任意一條曲線轉(zhuǎn)化為準(zhǔn)確的數(shù)學(xué)公式琐驴。 Bezier 曲線是用一系列點來控制曲線狀態(tài)的。
貝塞爾曲線中有一些比較關(guān)鍵的名詞秤标,解釋如下:
數(shù)據(jù)點:通常是指一條路徑的起始點和終止點
-
控制點:控制點決定了一條路徑的彎曲軌跡绝淡,根據(jù)控制點的個數(shù),貝塞爾曲線被分為一階貝塞爾曲線(0個控制點)苍姜、二階貝塞爾曲線(1個控制點)牢酵、三階貝塞爾曲線(2個控制點),以此類推衙猪。
Android中的貝塞爾曲線模擬
一般的開發(fā)者只考慮二階貝塞爾曲線和三階貝塞爾曲線馍乙,SDK也只提供了二階和三階的API調(diào)用。對于再高階的貝塞爾曲線垫释,通乘扛瘢可以將曲線拆分成多個低階的貝塞爾曲線,也就是所謂的降階操作饶号。分別是下列方法
二階 Path.quadTo()和rQuadTo() 前者基于絕對坐標(biāo)铁追,后者基于相對坐標(biāo)。
三階 Path.cubicTo()和rCubicTo() 前者基于絕對坐標(biāo)茫船,后者基于相對坐標(biāo)琅束。(參數(shù)比二階多了一個控制點)
我只是想畫一個潤滑點的圓弧,所以使用Path.quadTo()方法來繪制圓弧
quadTo(float x1, float y1, float x2, float y2)
Add a quadratic bezier from the last point, approaching control point (x1,y1), and ending at (x2,y2).
把兩條線反向延長算谈,交于一點涩禀,這個點就是控制點。(別問我為啥然眼,這個曲率就是剛剛好)
x2,y2是終點的坐標(biāo)艾船,默認是忽略起始坐標(biāo)的(起始坐標(biāo)就是你筆在的位置)
算控制點的過程比較難受,就省略啦高每。
然后在activity里面和fragment扯上關(guān)系就好了屿岂。
碰到的一些注意點
1. Invalidate方法實現(xiàn)界面刷新,但是Invalidate不能直接在子線程中調(diào)用
postInvalidate()可以在子線程中被調(diào)用
2. 不要在布局和繪圖期間創(chuàng)建對象
3. 寫自定義view的時候要注意Android的事件分發(fā)機制
dispatchTouchEvent(view的方法)---->onTouch(setontouchlistener)---->onTouchEvent(view的方法)----->onClick(setonclicklistener)
如果是通過重寫onTouchEvent()來執(zhí)行邏輯代碼鲸匿,那么給控件設(shè)置setonclicklistener就無效了爷怀。
具體的代碼可以查看github倉庫 點我跳轉(zhuǎn)