Tips:由于簡書好像不支持Latex公式,所以為了效果门粪,有關(guān)公式部分截取了我發(fā)表在CSDN上的博文泪酱,地址:AZZ的博客
相信很多朋友和我一樣很喜歡QQ上“一鍵退朝”的功能,就是把紅點從它原本的地方拉走离赫,消息提醒也就沒有了。
直到如今我還是覺得這個功能很酷炫塌碌!于是想自己實現(xiàn)一番渊胸,經(jīng)過一番調(diào)查知道拉伸其實就是由兩個圓加上兩條貝塞爾曲線組成的形狀。
來看看騰訊設(shè)計師是怎么設(shè)計出來的吧:《QQ手機(jī)版 5.0“一鍵下班”設(shè)計小結(jié)》
看完了這個對實現(xiàn)思路有很大的幫助台妆,可是我還是不能知道具體是怎么計算實現(xiàn)的翎猛,網(wǎng)上大部分的教程都是假想成了兩個同樣大小的圓來計算,這太取巧了接剩!因為同樣大小的圓兩條外公切線是平行的切厘,同一個圓上的公切點相連是會垂直于連心線的,但是大小不同的圓并沒有這個特殊性懊缺!
另外網(wǎng)上也有很多仿照的項目疫稿,可是看算法看得頭都大了也不明白為什么是這樣算的!經(jīng)過兩天的研究鹃两,把初中數(shù)學(xué)(圓遗座、三角函數(shù)等相關(guān)知識)好好復(fù)習(xí)了一遍,終于搞清楚了其中算法俊扳,現(xiàn)在跟我一起來看看吧途蒋!
1.得到連心線
通過觀察可以發(fā)現(xiàn),在“一鍵退朝”這個功能當(dāng)中馋记,有一個小圓固定在原來坐標(biāo)位置不動的号坡,只是半徑會發(fā)生變化,另一個大圓是跟隨著我們手指滑動到屏幕的位置來確定圓心坐標(biāo)的梯醒,一般大圓的半徑是固定的宽堆。
建立兩圓的相對坐標(biāo)系:
PS:在移動端的坐標(biāo)系 y 軸是向下的。
假設(shè)某一個時刻茸习,兩圓的狀態(tài)如圖日麸,我們現(xiàn)在可以確定的是小圓的圓心坐標(biāo) O 為(startX, startY),大圓的圓心坐標(biāo) P0 為 (x0, y0)代箭,以及小圓的半徑 r 和大圓的半徑 R 墩划。
那么首先可以把連心線求出來!也就是 O P0 的距離嗡综。
2.求切點坐標(biāo)
復(fù)習(xí)一下初中數(shù)學(xué):
兩個外離的圓乙帮,一定有兩條外公切線。若兩圓半徑相同极景,則兩外公切線平行察净;否則相交于一點,且該點與兩圓心在同一直線盼樟。
我們再作一張有公切線的圖:
切點為 P1氢卡、P2、P3晨缴、P4译秦,我們現(xiàn)在目的就要求出這四個點,然后就能夠在程序中畫出切線击碗。
整個算法最難的地方恐怕就是求這四個點了筑悴,我們需要借助作圖來幫助計算,這之前還需要先復(fù)習(xí)下定理:
圓心和切點的連線一定垂直于過該點的公切線
再作幾個輔助點 A稍途、B阁吝、C、D械拍,AB 表示以大圓圓心為原點的坐標(biāo)系的 x 軸的兩端突勇,CD 表示以小圓圓心為原點的坐標(biāo)系的 x 軸的兩端,
3.求剩下兩個切點的坐標(biāo)
一開始我以為 P3坷虑、P4 的算法和 P1甲馋、P2 一樣,就是把上面的減號換成加號就可以了猖吴。可是后來驗證后發(fā)現(xiàn)不對挥转, P3海蔽、P4 不能直接使用 β 進(jìn)行運算。
?為了能愉快閱讀绑谣,再來復(fù)習(xí)一下各種拉丁希臘符號叫法:
?α 阿爾法 β 貝塔 γ 伽瑪 δ 德爾塔 ε 伊普西隆 ζ 澤塔
如上圖作輔助線党窜。
4.畫貝塞爾曲線
把四個切點坐標(biāo)求出來了,后面就簡單了借宵,現(xiàn)在就是以切線為原軸幌衣,畫貝塞爾曲線了,不過我們還缺少一個控制點的坐標(biāo)。
4.1 科普貝塞爾
怕有不清楚貝塞爾曲線的朋友豁护,我科普一下先哼凯,簡單來說就是求一段平滑曲線的公式。
如果我們把畫一條直線分為進(jìn)度100%的話楚里,那么當(dāng)進(jìn)度為0%断部,12%,58%班缎,74%時蝴光,畫線的狀態(tài)為(注意紅色部分末的黑色端點,灰色部分為路徑指示)
那么把所有時刻的黑點連接起來就構(gòu)成了直線:
這個概念應(yīng)該比較容易接受达址,好了繼續(xù)蔑祟。
二次貝塞爾曲線(最簡單的貝塞爾曲線)的作法首先需要兩個點確定一條直線,另外在直線外確定一點(即控制點)沉唠,然后此時三點會形成三個線段疆虚,即下圖的P0 P2、P0 P1和 P1 P2$(其實不用關(guān)注 P0 P2)
這只是進(jìn)度為0時候的狀態(tài)右冻,按照上面概念装蓬,當(dāng)進(jìn)度 t 從 0 變化到 100 時的某一個時刻,比如 30, 66 ,99纱扭,那么各個時刻 P0 P1 和 P1 P2 的狀態(tài)為
可以發(fā)現(xiàn)牍帚,在 P0 P1 和 P1 P2 上有一直運動的兩個點,我們將這兩個點連接起來又形成一段新的線段乳蛾,而在不同時刻暗赶,在這個新線段上同樣會有一個運動的點,這個點也遵守 t 的變化肃叶。
把所有時刻的黃色點連接起來蹂随,就形成了二階貝塞爾曲線。
還不能理解的可以看下這個視頻 - > 《bezier curve原理》- > 只要看就好因惭,聽不懂英文的可以把聲音關(guān)掉岳锁。
費這么大勁把二階貝塞爾講了一遍,我們這里其實也只用到了二階蹦魔,高階我就不講了激率,一通百通。
4.2.尋找控制點
那么現(xiàn)在線段已經(jīng)能確定了勿决,就是兩條公切線線段(P1P2乒躺、P3P4),那么控制點在哪呢低缩?
這個其實有點靠猜了=嘉冒。= 一開始我覺得應(yīng)該在連心線的中點,其實實現(xiàn)后效果也還行,后來參照騰訊設(shè)計師的想法效果更好讳推,他令 P1P2 的控制點為 P1P4 的中點顶籽,令 P3P4 的控制點為 P2P3 的中點。
軟件實現(xiàn)效果對比(上邊控制點是連心線的中點娜遵,下邊是騰訊設(shè)計師提出的控制點):
我個人覺得下邊效果更好蜕衡,也不得不佩服TX設(shè)計師的聰明才智,讓我自己想可能永遠(yuǎn)也想不到设拟。
至于求 P1P4 和? P2P3 的中點不難吧慨仿?連四個坐標(biāo)點都求出來了,直接算就可以了纳胧!
---
源碼地址:https://github.com/Xieyupeng520/AZMetaBall(還會不斷完善的镰吆,求星星^3^)
---
References:
《QQ手機(jī)版 5.0“一鍵下班”設(shè)計小結(jié)》
《【Android開源項目解析】QQ“一鍵下班”功能實現(xiàn)解析——學(xué)習(xí)Path及貝塞爾曲線的基本使用》
本教程為了方便講解有篡改原圖,還望原圖作者見諒跑慕!