作者簡(jiǎn)介 原創(chuàng)微信公眾號(hào)郭霖 WeChat ID: guolin_blog
本篇來(lái)自Ulez的投稿森爽,分享了一個(gè)炫酷的ViewPager指示器,彈性十足,希望大家喜歡行楞。
Ulez的博客地址:
http://blog.csdn.net/s122ktyt
正文
去年在是某個(gè)Android群了看到有人發(fā)了一個(gè)設(shè)計(jì)圖,覺(jué)得很好土匀。想自己實(shí)現(xiàn)一下子房,到上網(wǎng)搜了一些資料,比如參考:
http://www.reibang.com/p/791d3a791ec2
這位兄弟已經(jīng)把如何繪制一個(gè)彈性的圓寫的很詳細(xì)了,在此對(duì)他表示感謝证杭。不過(guò)他沒(méi)有完整實(shí)現(xiàn)這個(gè)自定義控件田度,所以還是自己動(dòng)手實(shí)現(xiàn)一個(gè),但是我覺(jué)得效果和原設(shè)計(jì)還有差距解愤,一直沒(méi)寫博客镇饺。這幾天抽時(shí)間把里面的效果在改了改,順便也把博客寫了琢歇。先上效果圖:
下面開(kāi)始分析寫得思路兰怠,先來(lái)個(gè)方法截圖:
用貝塞爾曲線繪制一個(gè)圓需要12個(gè)點(diǎn),如上圖所示李茫。然后在繪制時(shí)用 mPath.cubicTo() 依次連接揭保,canvas.drawPath(mPath, mPaint) 就能繪制一個(gè)完整的圓了,彈性圓就是在此基礎(chǔ)上調(diào)整 p的參數(shù)魄宏。比如 {p2,p3,p4},增加X(jué)坐標(biāo)秸侣,會(huì)使圓向右凸起。
代碼中 XPoint 為x相同的一組點(diǎn):p2宠互,p3味榛,p4 和 p8,p9予跌,p10搏色,YPoint 同理。代碼中的mc對(duì)應(yīng)圖中的M券册,繪制圓時(shí)這個(gè)值是固定的频轿,理論參考:
How to create circle with Bézier curves?
http://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves
p1={p5,p6,p7}.,p3={p11,p0,p1},p2={p2,p3,p4},p4={p8,p9,p10},radius 為圓半徑烁焙。
resetP() 在完成選項(xiàng)切換時(shí)都需要調(diào)用一下航邢,重置繪制的圓形形狀,不然有時(shí)候會(huì)繪制不規(guī)則的圓骄蝇,造成這個(gè)的原因是view刷新頻率是有限的膳殷,有些臨界狀態(tài)直接就跳過(guò)了,導(dǎo)致參數(shù)沒(méi)跟著變化就繪制了圖像九火。
下面根據(jù)兩種切換viewpager的方式分析:
第一種情況赚窃,點(diǎn)擊 indicator 切換
在 onTouchEvent 計(jì)算將要切換的位置,調(diào)用 startAniTo(int currentPos, int toPos),? animator 監(jiān)聽(tīng) setTouchAble(!animating) 是禁止動(dòng)畫未結(jié)束用戶又去手動(dòng)滑動(dòng) viewpager 切換吃既。
下面是?dispatchDraw 方法,為了更簡(jiǎn)單看懂考榨,我就截取 position 從左向右的情況;處理臨界情況很重要鹦倚,沒(méi)處理好你會(huì)發(fā)現(xiàn)繪制出來(lái)的是什么鬼河质!
mCurrentTime 是動(dòng)畫變化時(shí)刷新的值,從0到1,根據(jù)這個(gè)值重繪時(shí)計(jì)算圓的坐標(biāo)掀鹅。我將mCurrentTime 分為下列幾種狀態(tài):
mCurrentTime == 0:
這個(gè)狀態(tài)就是根據(jù)position繪制正常的圓散休。
mCurrentTime > 0 && mCurrentTime <= 0.2:
這個(gè)此時(shí)圓向右凸起,但是原本的canvas.translate和上個(gè)狀態(tài)不變乐尊,所以是圓停止在當(dāng)前位置并且慢慢凸起的效果戚丸。
mCurrentTime > 0.2 && mCurrentTime <= 0.5:
這時(shí)圓開(kāi)始平移,canvas.translate(startX + (mCurrentTime - 0.2f) * distance / 0.7f, startY); 那為啥是除以0.7呢扔嵌?因?yàn)?到0.2沒(méi)平移限府,0.2到0.9平移完成,0.9到1處理回彈痢缎。平移時(shí)間只有0.9-0.2=0.7胁勺,這段時(shí)間要完成一個(gè)distance的距離的平移。同時(shí)之前圓向右凸起時(shí),p2組的點(diǎn)x坐標(biāo)總共增加了一個(gè)radius(這個(gè)決定凸起程度)《揽酰現(xiàn)在要把它弄回對(duì)稱橢圓署穗,所以p1組和p3組的點(diǎn)要右移半個(gè)radius,同時(shí)mc調(diào)整一下使橢圓不那么尖嵌洼;
mCurrentTime > 0.5 && mCurrentTime <= 0.8:
p1和p3的X坐標(biāo)繼續(xù)往右移案疲,mc逐漸重置為原來(lái)大小,效果就是圓的最右端固定不變麻养,左邊的凸起縮回去
mCurrentTime > 0.8 && mCurrentTime <= 0.9:
左邊的p4.組點(diǎn)往右平移過(guò)頭褐啡,圓形成凹陷
mCurrentTime > 0.9 && mCurrentTime < 1:
這個(gè)階段是處理回彈,p4.組點(diǎn)x逐漸恢復(fù)正常鳖昌。表現(xiàn)為回彈恢復(fù)為標(biāo)準(zhǔn)圓春贸。
mCurrentTime == 1:
position 此時(shí)真實(shí)改變了,重置為正常的圓遗遵。
以上的每個(gè)階段在進(jìn)入下個(gè)階段時(shí),都需要重置一下p坐標(biāo)逸嘀,因?yàn)関iew刷新頻率是有限的车要,有些結(jié)束的臨界狀態(tài)值直接就跳過(guò)了,導(dǎo)致參數(shù)沒(méi)跟著變化就繪制了圖像崭倘。
第二種情況翼岁,拖動(dòng)viewpager切換
viewPager.addOnPageChangeListener,在 onPageScrolled 中調(diào)用?updateDrop(position, positionOffset, positionOffsetPixels),更新位置。這里需要注意的是點(diǎn)擊 indicator 也會(huì)回調(diào)司光, 若不進(jìn)行判斷會(huì)造成重復(fù)的移動(dòng)琅坡,所以之前在動(dòng)畫開(kāi)啟的監(jiān)聽(tīng)時(shí)設(shè)置 boolean animating 值。
這里我用 mCurrentTime = position + positionOffset - (int) (position + positionOffset); 然而這樣計(jì)算是有問(wèn)題的残家,比如向左滑動(dòng)榆俺,它是從0到0.9幾,然后突變?yōu)?,為了這個(gè)判斷添加了一個(gè) lastCurrentTime 茴晋,根據(jù)接近接近0或1更改為0或1陪捷。
總結(jié)一下,需要注意的是 mCurrentTime?狀態(tài)的劃分诺擅、臨界狀態(tài)的處理市袖、以及在合適的位置重置p坐標(biāo),在寫的過(guò)程幾次碰到繪制的圖像莫名其妙烁涌,這是p的坐標(biāo)問(wèn)題苍碟,查找原因一般也是狀態(tài)沒(méi)重置。
源碼地址:
https://github.com/Ulez/DropIndicator
完撮执。微峰。。二打。县忌。。继效。症杏。。瑞信。厉颤。。凡简。逼友。。秤涩。帜乞。稳析。豌拙。。蒜焊。
文章原創(chuàng)作者GuoLin 書籍推薦
郭林大神原創(chuàng)android 書籍:《第一行代碼 android》