八、自定義View之使用貝塞爾曲線繪制可拖拽小紅點

該項目屬于繼承自View的自定義控件。

效果圖如下:




1.靜態(tài)繪制粘性控件

粘性控件由兩個點和中間的貝塞爾曲線組成。效果圖如下:

靜態(tài)繪制可拖拽小圓點

分析圖如下:


靜態(tài)繪制粘性控件分析圖

總體來說:粘性控件兩個小圓點之間的區(qū)域使用貝塞爾曲線繪制,貝塞爾曲線有三個點,起始點,終點和控制點。第一條貝塞爾曲線起始點為固定圓的上半圓弧水平切點,第二條貝塞爾曲線的起始點為固定圓下半圓弧水平方向的切點。兩條貝塞爾曲線的終點和控制點起始狀態(tài)的位置如圖所示。終點為拖拽圓上下半圓弧水平方向的切點,控制點是圓心連線的中點。后面動態(tài)繪制時,兩條貝塞爾曲線的終點和控制點是隨著拖拽圓的移動而改變的,這是后話。

1)在onDraw()中繪制兩個小圓點:

繪制兩個圓

2) 繪制貝塞爾曲線,使用Path類

首先確定貝塞爾曲線的起始點,終點坐標(biāo)。如下圖分析所示:

貝塞爾曲線起始位置點坐標(biāo)分析

分別獲得了兩條貝塞爾曲線三個點的坐標(biāo),首先把起點,終點封裝起來,避免用錯。

開始繪制貝塞爾曲線,使用Path類,具體用法代碼中已注釋

其中需要注意的是,貝塞爾曲線是一個閉合的曲線,如果只有兩個點,它會自動連接起點和終點,因此我們畫第二條貝塞爾曲線時,直接把第二條的終點和第一條的終點連接起來,將4個點逆時針連接,lineTo(x,y)是畫連線的意思,將曲線終點連接到(x,y) moveTo(x,y)是直接跳到(x,y)

此時,靜態(tài)的拖拽小圓點已經(jīng)繪制完成,明天更新動態(tài)拖拽小紅點的內(nèi)容。

2、繪制動態(tài)拖拽小紅點

原理:根據(jù)手指在屏幕上的觸摸點和MOVE事件,更改drag圓的圓心坐標(biāo),根據(jù)圓心坐標(biāo)和斜率求出繪制貝塞爾曲線需要的5個點。需要注意的是,在拖拽的過程中,這5個點是一直隨著dragCenter的變化而變化的。

如圖所示:

如圖所示:5個點分別是

1.controlPoint控制點? 2.stickyPointp[0],dragPoint[0]第一條貝塞爾曲線的起點和終點。3.dragPoint[1],stickyPoint[1] 第二條貝塞爾曲線的起點和終點。

那么怎么樣求出這5個點呢? 一步步來

1、 controlPoint 兩圓圓心連線的黃金分割點。根據(jù)兩圓圓心坐標(biāo)和比例0.618求出該點坐標(biāo)

2.求出斜率

3.根據(jù)斜率求出4個點

代碼如下:

根據(jù)dragCenter的改變,動態(tài)求出5個點之后,就可以動態(tài)的繪制貝塞爾曲線,我們需要在onTouchEvent中,把Down 和Move 事件下獲得手指移動的坐標(biāo),作為dragCenter的坐標(biāo),并且每次進行onToucheEvent時,都要對畫面進行重繪。每次重繪都會更新點坐標(biāo),完成拖拽行為在屏幕上的實現(xiàn)。

onTouchEvent()代碼的實現(xiàn):

此時,效果如下:

可以看到,手指點到的位置,與dragCenter稍微有點偏移,這是因為獲取的是點相對于屏幕的x,y坐標(biāo),而StatusBar 占了畫布一點距離。因此,我們需要把畫布整體往上偏移即可。

canvas.translate(0, -GeometryUtil.getStatusBarHeight(getResources()));

一些優(yōu)化:(為什么每次傳入值,屏幕上的值就可以動態(tài)的變化呢,這是因為在onTounchEvent

中調(diào)用了invalidate()重繪界面)

優(yōu)化1.固定圓的半徑隨著兩圓之間的距離變大,而不斷的變小。到達一定的距離后就消失不見。

首先解決stickyRadius隨著兩圓之間的距離變大而不斷變小。

代碼如下:在onDraw()中,每次重繪界面都會改變stickyRadius值

然后解決,拖拽到一定程度時,中間連接的部分?jǐn)嗟?,固定圓消失。

首先設(shè)置一個boolean isDragOut = true;

在onTouchEvent()中,拖拽的過程中,即MOVE事件中,判斷兩圓圓心的距離是否大于設(shè)定的最大值,這里是200,如果大,則將isDragOut = false;在onDraw()中 不再繪制貝塞爾曲線和固定圓部分,代碼如下:

onDraw()中

優(yōu)化2.手松開時拖拽圓的優(yōu)化。

分幾種情況

1.手松開時,已經(jīng)拖拽出了最大范圍,此時拖拽圓回去。

2.手松開時,沒有拖拽出最大范圍,此時拖拽圓以動畫的形式彈回去

3.手松開時,沒有拖拽出最大范圍,但曾經(jīng)拖拽出最大范圍過,直接回去,不用動畫的狀態(tài)彈回去

代碼如下

至此,自定義View暫時告一段落,等我把谷歌市場和華為市場兩個項目寫完,再繼續(xù)更新一些比較難的自定義View的博客,參考Hencoder的公眾號,做一些現(xiàn)在比較常用的自定義View。

今年的計劃基本上是這樣:

1.谷歌市場 2.華為市場 3.java數(shù)據(jù)結(jié)構(gòu)和算法? java編程思想 學(xué)完了Android中的東西,就開始學(xué)習(xí)后端的知識

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

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

  • 一、Path常用方法表 二.Path詳解 上一次除了一些常用函數(shù)之外,講解的基本上都是直線,本次需要了解其中的曲線...
    呂侯爺閱讀 1,749評論 1 6
  • 前言 之前沒有見到有封裝好的類似QQ小紅點的控件,雖然公司項目中并沒有使用到該效果,不過出于練習(xí)與回顧的角度決定自...
    小甜李子閱讀 548評論 0 0
  • 前一篇文章講了Path繪制直線以及各種基本圖形,這篇文主要說Path繪制曲線,就是曲線中非常有名的貝賽爾曲線。貝賽...
    Jackson杰閱讀 2,342評論 0 13
  • 夜微涼,清風(fēng)偶拂面,聞得蛙鳴陣陣。且看蒼穹,皓月千里,繁星璀璨,人月相對,無言卻生萬分嘆! 古往今來,時移世易。陰...
  • 魏麗玲@4月23日 領(lǐng)導(dǎo)者的資質(zhì)#8期#關(guān)愛組【學(xué)委】 河北惠友集團 一、【知~勤學(xué)】 《領(lǐng)導(dǎo)者的十項資質(zhì)》3遍 ...
    qin123456閱讀 206評論 0 0

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