該項(xiàng)目屬于繼承自View的自定義控件。
效果圖如下:
1.靜態(tài)繪制粘性控件
粘性控件由兩個(gè)點(diǎn)和中間的貝塞爾曲線組成抖仅。效果圖如下:
分析圖如下:
總體來說:粘性控件兩個(gè)小圓點(diǎn)之間的區(qū)域使用貝塞爾曲線繪制交煞,貝塞爾曲線有三個(gè)點(diǎn)咏窿,起始點(diǎn),終點(diǎn)和控制點(diǎn)素征。第一條貝塞爾曲線起始點(diǎn)為固定圓的上半圓弧水平切點(diǎn)翰灾,第二條貝塞爾曲線的起始點(diǎn)為固定圓下半圓弧水平方向的切點(diǎn)。兩條貝塞爾曲線的終點(diǎn)和控制點(diǎn)起始狀態(tài)的位置如圖所示稚茅。終點(diǎn)為拖拽圓上下半圓弧水平方向的切點(diǎn)纸淮,控制點(diǎn)是圓心連線的中點(diǎn)。后面動(dòng)態(tài)繪制時(shí)亚享,兩條貝塞爾曲線的終點(diǎn)和控制點(diǎn)是隨著拖拽圓的移動(dòng)而改變的咽块,這是后話。
1)在onDraw()中繪制兩個(gè)小圓點(diǎn):
2) 繪制貝塞爾曲線欺税,使用Path類
首先確定貝塞爾曲線的起始點(diǎn)侈沪,終點(diǎn)坐標(biāo)。如下圖分析所示:
分別獲得了兩條貝塞爾曲線三個(gè)點(diǎn)的坐標(biāo)晚凿,首先把起點(diǎn)亭罪,終點(diǎn)封裝起來,避免用錯(cuò)歼秽。
開始繪制貝塞爾曲線应役,使用Path類,具體用法代碼中已注釋
其中需要注意的是,貝塞爾曲線是一個(gè)閉合的曲線箩祥,如果只有兩個(gè)點(diǎn)院崇,它會(huì)自動(dòng)連接起點(diǎn)和終點(diǎn),因此我們畫第二條貝塞爾曲線時(shí)袍祖,直接把第二條的終點(diǎn)和第一條的終點(diǎn)連接起來底瓣,將4個(gè)點(diǎn)逆時(shí)針連接,lineTo(x,y)是畫連線的意思蕉陋,將曲線終點(diǎn)連接到(x,y) moveTo(x,y)是直接跳到(x,y)
此時(shí)捐凭,靜態(tài)的拖拽小圓點(diǎn)已經(jīng)繪制完成,明天更新動(dòng)態(tài)拖拽小紅點(diǎn)的內(nèi)容凳鬓。
2茁肠、繪制動(dòng)態(tài)拖拽小紅點(diǎn)
原理:根據(jù)手指在屏幕上的觸摸點(diǎn)和MOVE事件,更改drag圓的圓心坐標(biāo)村视,根據(jù)圓心坐標(biāo)和斜率求出繪制貝塞爾曲線需要的5個(gè)點(diǎn)。需要注意的是酒奶,在拖拽的過程中蚁孔,這5個(gè)點(diǎn)是一直隨著dragCenter的變化而變化的。
如圖所示:
如圖所示:5個(gè)點(diǎn)分別是
1.controlPoint控制點(diǎn)? 2.stickyPointp[0],dragPoint[0]第一條貝塞爾曲線的起點(diǎn)和終點(diǎn)惋嚎。3.dragPoint[1],stickyPoint[1] 第二條貝塞爾曲線的起點(diǎn)和終點(diǎn)杠氢。
那么怎么樣求出這5個(gè)點(diǎn)呢? 一步步來
1另伍、 controlPoint 兩圓圓心連線的黃金分割點(diǎn)鼻百。根據(jù)兩圓圓心坐標(biāo)和比例0.618求出該點(diǎn)坐標(biāo)
2.求出斜率
3.根據(jù)斜率求出4個(gè)點(diǎn)
代碼如下:
根據(jù)dragCenter的改變,動(dòng)態(tài)求出5個(gè)點(diǎn)之后摆尝,就可以動(dòng)態(tài)的繪制貝塞爾曲線温艇,我們需要在onTouchEvent中,把Down 和Move 事件下獲得手指移動(dòng)的坐標(biāo)堕汞,作為dragCenter的坐標(biāo)勺爱,并且每次進(jìn)行onToucheEvent時(shí),都要對畫面進(jìn)行重繪讯检。每次重繪都會(huì)更新點(diǎn)坐標(biāo)琐鲁,完成拖拽行為在屏幕上的實(shí)現(xiàn)。
onTouchEvent()代碼的實(shí)現(xiàn):
此時(shí)人灼,效果如下:
可以看到围段,手指點(diǎn)到的位置,與dragCenter稍微有點(diǎn)偏移投放,這是因?yàn)楂@取的是點(diǎn)相對于屏幕的x奈泪,y坐標(biāo),而StatusBar 占了畫布一點(diǎn)距離。因此段磨,我們需要把畫布整體往上偏移即可取逾。
canvas.translate(0, -GeometryUtil.getStatusBarHeight(getResources()));
一些優(yōu)化:(為什么每次傳入值,屏幕上的值就可以動(dòng)態(tài)的變化呢苹支,這是因?yàn)樵趏nTounchEvent
中調(diào)用了invalidate()重繪界面)
優(yōu)化1.固定圓的半徑隨著兩圓之間的距離變大砾隅,而不斷的變小。到達(dá)一定的距離后就消失不見债蜜。
首先解決stickyRadius隨著兩圓之間的距離變大而不斷變小晴埂。
代碼如下:在onDraw()中,每次重繪界面都會(huì)改變stickyRadius值
然后解決寻定,拖拽到一定程度時(shí)儒洛,中間連接的部分?jǐn)嗟簦潭▓A消失狼速。
首先設(shè)置一個(gè)boolean isDragOut = true;
在onTouchEvent()中琅锻,拖拽的過程中,即MOVE事件中向胡,判斷兩圓圓心的距離是否大于設(shè)定的最大值恼蓬,這里是200,如果大僵芹,則將isDragOut = false处硬;在onDraw()中 不再繪制貝塞爾曲線和固定圓部分,代碼如下:
onDraw()中
優(yōu)化2.手松開時(shí)拖拽圓的優(yōu)化拇派。
分幾種情況
1.手松開時(shí)荷辕,已經(jīng)拖拽出了最大范圍,此時(shí)拖拽圓回去件豌。
2.手松開時(shí)疮方,沒有拖拽出最大范圍,此時(shí)拖拽圓以動(dòng)畫的形式彈回去
3.手松開時(shí)茧彤,沒有拖拽出最大范圍案站,但曾經(jīng)拖拽出最大范圍過,直接回去棘街,不用動(dòng)畫的狀態(tài)彈回去
代碼如下
至此蟆盐,自定義View暫時(shí)告一段落,等我把谷歌市場和華為市場兩個(gè)項(xiàng)目寫完遭殉,再繼續(xù)更新一些比較難的自定義View的博客石挂,參考Hencoder的公眾號,做一些現(xiàn)在比較常用的自定義View险污。
今年的計(jì)劃基本上是這樣:
1.谷歌市場 2.華為市場 3.java數(shù)據(jù)結(jié)構(gòu)和算法? java編程思想 學(xué)完了Android中的東西痹愚,就開始學(xué)習(xí)后端的知識