自定義view實現超萌動感小炸彈
宣告:本文章獨家授權微信公眾號碼個蛋原創推文
Hello
,小夥伴們,我回來了。這些日子有的小夥伴問我怎麼沒有更新了。這個其實是有原因,首先,最近有點忙。其次沒有看到什麼覺得好玩的動畫!最後,就是我更新過了!!ThreadLocal
原始碼完全解析,只是你們原始碼不感冒,然後你們忽略了!!!!忽略了!!!還有,我其實有更新一個薄荷捲尺,只是覺得有點簡單,而且還像也有什麼好講的,所以只是上傳到github
,沒有文章。
客套話已經完了,現在開始我們的超萌動感小炸彈之旅。
首先,我還是先感謝一下作者,設計出這麼棒的動畫!!設計出處點我。
效果如下,Amazing:
再來看
android
的實現效果。
下面我們和自定義view實現超萌動感天氣小太陽一樣,開始解析動畫!(沒看過天氣小太陽的朋友可以先去看天氣小太陽,有些天氣小太陽講過的套路將不再講,同時需要掌握path
、camera
、貝塞爾曲線等,不然部分程式碼可能會引起不適)。
我們先把靜態view
繪製出來,然後再實現動畫,Let's go。
1.地板
可以看到地板其實就是一條直線。然後中間兩個缺口。這要個麼實現呢?看到小太陽的小夥伴可能都會說,這很簡單。只要畫一線直線然後覆蓋兩個白的區間就可以了。的確這可以實現,但是仔細觀察可以發現下方的缺口是兩個半圓加矩形實現的,這樣的話就有點麻煩,而且不方便缺口位置的移動。那有什麼簡單的方法呢?有,那就是使用Path
進行繪畫一條直線,然後通過設定圓筆頭,再設定DashPathEffect
(實現虛線,一段畫,一段不畫的效果,可以自由控制各段長度)來實現間隔(本view的缺口都是使用此特性實現的,不熟悉的小夥伴可以去看一下),程式碼如下:
float[] groundEffectFloat=new float[] {bombLineWidth/4,bombLineWidth/2+bombLineWidth,bombLineWidth*2,bombLineWidth/3*2+bombLineWidth,getMeasuredWidth(),0};//設定畫與不畫所佔長度
groundDashPathEffect=new DashPathEffect(groundEffectFloat,0);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(bombLineColor);
mPaint.setPathEffect(groundDashPathEffect);//設定虛線效果
mPath.reset();
mPath.moveTo(bombLineWidth/2,getMeasuredHeight()-bombLineWidth/2);
mPath.lineTo(getMeasuredWidth()-bombLineWidth/2,getMeasuredHeight()-
bombLineWidth/2);
canvas.drawPath(mPath,mPaint);
2.身體的邊框
仔細一看!聰明的你一定會說太簡單了,這不就是一個圓然後再用
DashPathEffect
實現缺口不就可以了!!嗯,對,就是這樣的。直接放程式碼:
mPaint.setPathEffect(bodyDashPathEffect);
mPaint.setColor(bombLineColor);
mPaint.setStyle(Paint.Style.STROKE);
mPath.reset();
mPath.addCircle(bombCenterX,bombCenterY,bodyRadius,
Path.Direction.CW);
canvas.drawPath(mPath,mPaint);
canvas.restore();
簡單!簡單的不能再簡單了,下面看身體
3.身體
可以發現身體其實也就是一個圓,然後加上左上角的高光。那麼高光是怎麼實現的呢?
三個點的高光,很簡單的,用Path
畫弧,然後使用DashPathEffect
效果,完美。
那麼另一個高光呢?看圖。
可以看到就是條圓弧和一個路徑合成的,然後裁剪保持圓內。路徑的形成就是取弧度的兩個點,然後用貝塞爾曲線進行繪製,控制點位於弧度中分線中(下圖紅點)。
程式碼如下:(部分程式碼,左上角高光的,其它的請檢視原始碼)
//左上角的光邊
mPaint.setPathEffect(null);
mRectF.set(bombCenterX-bodyRadius+bombLineWidth/2,bombCenterY-bodyRadius+bombLineWidth/2
,bombCenterX+bodyRadius-bombLineWidth/2,getMeasuredHeight()-bombLineWidth-bombLineWidth/2);
canvas.drawArc(mRectF,160,100,false,mPaint);
//拼接光邊
mPath.reset();
mPath.addCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2, Path.Direction.CCW);
canvas.save();
canvas.clipPath(mPath);//裁剪圓內
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(lightColor);
canvas.drawPath(mBodyLightPath,mPaint);
canvas.restore();
4.臉
大家可以看到,好你有點複雜的,其實還好。這裡是因為使用了Z
軸旋轉,看起來有點複雜,那我們移到中間。
好像簡單了,眼睛和酒窩簡單,4個圓!!嘴巴,這個。。。這個好像有點噁心啊。其實不然,看圖。
其實就是一個圓然後再加上一個路徑圖就可以實現,紅點表示的是控制點。空心點表示節點。細心的朋友可能發現,不對啊。舌頭下面不全是紅的,和嘴巴是分開的。這裡只需要把嘴巴按比例縮小,然後和嘴巴做個Xfermode
就可以了。部分程式碼:
//畫舌頭 圓和嘴巴的縮放相交,mpath是嘴巴的路徑
int save=canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null,Canvas.ALL_SAVE_FLAG);
canvas.drawPath(mPath,mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
mPaint.setColor(Color.parseColor("#f34671"));
canvas.drawCircle(bombCenterX,mouthY+(mouthMaxY-mouthY)/8+bodyRadius/(5-1.4f*mouthOffsetPercent),bodyRadius/5,mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.scale(0.8f,0.8f,bombCenterX,(mouthMaxY+mouthY)/2);
canvas.drawPath(mPath,mPaint);
canvas.restoreToCount(save);
mPaint.setXfermode(null);
5.臉上的陰影(不知道叫什麼,暫時稱為陰影遮罩)
一看,個別好事的小夥伴說,你不會又讓我用貝塞爾曲線畫吧!這個不好找啊!!冷靜冷靜,這個實現如下:
如此簡單,兩個圓取紅圓未相交的部分。
//兩個圓相交產生陰影
int save=canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null,Canvas.ALL_SAVE_FLAG);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(bombShadowColor);
canvas.drawCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2,mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
canvas.translate(-bodyRadius/5,-bodyRadius/5);
mPaint.setColor(bombColor);
canvas.drawCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2,mPaint);
canvas.restoreToCount(save);
mPaint.setXfermode(null);
6.頭
小夥伴又要說了。這個不好畫,不好畫!!冷靜冷靜。這個其實更簡單。只要把頭放在身體的後面一層就可以了。看圖:
程式碼:
太簡單,我不想貼了,假裝我是程式碼
7.引線
這個引線,其實也就是一線曲線,貝塞爾曲線繼續上場(不解釋,不懂的請面壁去)。
8.爆炸效果
簡單的不太再簡單了,4個圓,半徑從大到小畫,中間然後挖空。so easy!!
int save = canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null,Canvas.ALL_SAVE_FLAG);
float distance = maxBlastCircleRadius/12;
//畫圓
mPaint.setColor(lightColor);
canvas.drawCircle(bombCenterX,circleY, currentBlastCircleRadius,mPaint);
mPaint.setColor(bombColor);
canvas.drawCircle(bombCenterX,circleY, currentBlastCircleRadius -distance,mPaint);
mPaint.setColor(bombLineColor);
canvas.drawCircle(bombCenterX,circleY, currentBlastCircleRadius -distance*2,mPaint);
mPaint.setColor(lightColor);
canvas.drawCircle(bombCenterX,circleY, currentBlastCircleRadius -distance*3,mPaint);
//掏空
if (blastCircleRadiusPercent >0.65) {
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
canvas.drawCircle(bombCenterX, circleY, currentBlastCircleRadius - maxBlastCircleRadius * 0.65f, mPaint);
mPaint.setXfermode(null);
}
canvas.restoreToCount(save);
到這裡,我們已經完成了一半,那就是小炸彈的顯示,現在到了動畫的時間了!再次出場
9.臉左右移動動畫
可以看到左右移動,在移動的時間然後我們只需要在畫臉的時間加一個偏移,然後在移動的過程中,會發現臉會繞炸彈身體的中心旋轉。所以程式碼如下
canvas.save();
mCamera.save();
mCamera.rotate(bombTBRotate,0,-bombLRRotate/3);
mMatrix.reset();
mCamera.getMatrix(mMatrix);
mCamera.restore();
mMatrix.preTranslate(-bombCenterX,-(bombCenterY));
mMatrix.postTranslate(bombCenterX,bombCenterY);
mMatrix.postTranslate(faceLROffset,faceTBOffset);
canvas.setMatrix(mMatrix);
使用camera
,進行z
軸的旋轉,然後再進行translate
左右移動,然後使用valueanimator
動畫對變偏移進行設定,搞定!在移動過程中,可以發現眼睛有眯下的效果。這個很簡單,可以把眼睛用橢圓來實現,保持寬度不變,改變高度就可以了。
10.身體頭部引線左右旋轉
這個就更簡單了,只需要在畫之前用camera
旋轉變換獲取martix
,然後對canvas
進行變換。
11.臉部上下移動
首先和臉部左右移動一樣,使用matrix.translate
進行上下移動。眼睛的變換也一樣。後面的眼睛放大效果,就是在變成圓的眼睛的時候,放大圓的半徑。
嘴巴的變換就相對比較複雜!看圖,高能預警,我也不知道我講不講得清楚!!!!
這是剛才畫嘴巴的圖!!!嘴巴動畫有兩個部分!!(以下語句可能會引起不適)
- 第一部分嘴角往兩邊移動,嘴巴變扁。這裡我們需要把
ab
兩點用屬性動畫往兩邊移動(兩邊的拐角點同樣移動),c
點往上方移動,然後回到原始位置。 - 第二部分是
ab
兩點往中間靠攏,直到ab
重合,同時ab
兩點往上移,de
的控制點同時拉長,直到形成一個橢圓。
不理解!!不理解再好好想象一下,空間想象能力。要是還想不懂,那就算了。畢竟平時用得不多。
12.炸彈引線,點燃效果
炸彈引線效果同樣分兩個部分
- 一個是引線變短,可以根據
PathMeasure
,獲取Path
的比例Path
(比如70%
的Path
),這樣我們就可以通過ValueAnimator
用一個0
到1
的比例來繪製引線變短的效果
//mHeadLinePath是引線的完整Path
mPathMeasure.setPath(mHeadLinePath,false);
mPath.reset();
mPathMeasure.getSegment(0,mPathMeasure.getLength()*headLinePercent,mPath,true);//根據比例獲取對應比例的引線
canvas.drawPath(mPath,mPaint);
- 第二部分是點燃的效果。其實就是一個金色的實心圓,然後一個紅色的圓邊框,中間白色,三個圓按不同的速率和極限做放大縮小動畫 (這裡原設計還加入了變色的功能,金色圓會變色,可以用
ArgbEvaluator
實現)。
13.爆炸動畫
和引線動畫型別,4個圓做放大縮小動畫,只是到一定的大小後,然後圓小漏空,並且漏空逐漸放大。
14.結語
好了,我們的超萌動感小炸彈到這裡就結束了。希望小夥伴們能有所收穫,掌握更多自定義view
的套路,更多分析方法,我們下次見。
相關文章
- avalonia實現自定義小彈窗
- 自定義View實用小技巧View
- 自定義view————廣告彈窗View
- 自定義View:畫布實現自定義View(折線圖的實現)View
- 自定義View:自定義屬性(自定義按鈕實現)View
- 小程式自定義modal彈窗封裝實現封裝
- Flutter自定義View的實現FlutterView
- 自定義view實現半圓環View
- 【朝花夕拾】Android自定義View篇之(十一)View的滑動,彈性滑動與自定義PagerViewAndroidView
- 自定義View實現箭頭沿圓轉動View
- 自定義簡單彈幕實現
- 自定義View:側滑選單實現View
- 自定義view實現圓角圖片View
- Jquery實現自定義訊息彈窗jQuery
- 深入瞭解View實現原理以及自定義View詳解View
- 微信小程式底部實現自定義動態Tabbar微信小程式tabBar
- 自定義圓形View:實現跟隨手指移動的小球View
- 自定義view之實現日曆介面(一)View
- 自定義view之實現日曆介面(二)View
- 自定義View:側滑選單動畫實現View動畫
- jQuery實現的自定義可以拖動的彈出層效果jQuery
- 自定義View-扭曲動效View
- 自定義View-波浪動效View
- 【朝花夕拾】Android自定義View篇之(四)自定義View的三種實現方式及自定義屬性詳解AndroidView
- 自定義VIEWView
- flutter-簡單實現找妹子自定義viewFlutterView
- Android自定義View實現文字輪播效果AndroidView
- Android自定義view實現數字時鐘AndroidView
- vue2 - element彈框自定義指令 實現拖動、縮放Vue
- iOS實現自定義的彈出檢視(popView)iOSView
- Android 自定義 View 實現橫行時間軸AndroidView
- Android自定義View:快遞時間軸實現AndroidView
- Android自定義View實現微信打飛機遊戲AndroidView遊戲
- 自定義View公式View公式
- Android自定義View:View(二)AndroidView
- Android 自定義View 滑動解鎖AndroidView
- Android自定義View之星球運動AndroidView
- 自定義View事件之進階篇(四)-自定義Behavior實戰View事件