目錄
前言
效果展示
影片一
影片一效果
貝賽爾曲線
代碼示例
影片二
影片二效果
時差影片
面向物件繪制
總結
前言
很多App啟動的時候會用到炫酷的開場影片,Android TV端也一樣,每一個不同的模塊,產品經理都可能設計了不同的開場影片,對于這些復雜的開場影片,最重要的是學會拆分,只要拆分得當,就會變成一個個普通的影片組合而成,今天給大家介紹一個曾經在專案中使用過的炫酷的開場影片,
效果展示

上面的圖片中展示了一個曾在專案中使用的開場影片,由于專案還還在線,所以僅僅截圖了其中一部分的影片,對于這樣一個影片,我們可以選擇放一張GIF圖片,但是對于每秒60幀的安卓來說,GIF的效果真的很難讓人滿意,而且GIF貌似不能做透明背景,這樣一來要做組合影片就難了,所以我們不得不考慮用原生技術來解決這樣一個影片效果,
這個影片可以拆分成三個影片,左邊紅色氣球一直左右搖擺,像是在風中搖曳,右邊一團紫色氣球上升,像是有人放飛了一簇氣球,紫色氣球飛完之后有一個橫幅逐漸展示, 最后橫幅的展示僅僅是個屬性影片,今天不多做介紹,今天主要介紹前兩個影片,
影片一
影片一效果
首先我們把第一個影片拆分出來,單獨展示的話,它是這樣的:

這個影片看似還比較簡單,我第一印象也是這樣,不就是一個氣球左右移動嗎?使用屬性影片或者幀影片都可以完成吧,實際操作中發現,下面的繩子是主要難點,繩子一端固定,一端隨氣球移動,而且繩子是曲線不是直線,這就排除了用屬性影片移動氣球的解決方案,幀影片理論上是可以的,只要分出足夠多幀就行,但是想要這么如絲般潤滑,幀數一定不少,幀數越多圖片就越多,app體積就越大,筆者采用的方法是一張圖片搞定,上面的氣球是一張圖片,左右移動,下面的繩子直接畫出來,這里就需要用到貝塞爾曲線,
貝賽爾曲線
貝塞爾曲線于1962年,由法國工程師皮埃爾·貝塞爾(Pierre Bézier)所廣泛發表,他運用貝塞爾曲線來為汽車的主體進行設計,貝塞爾曲線最初由 Paul de Casteljau 于1959年運用de Casteljau 演算法開發,以穩定數值的方法求出貝塞爾曲線,
需用到Path方法:
mPath.moveTo 移動到操作起始點坐標,不會進行繪制,只用于移動移影片筆
mPath.lineTo 從一個點連線到另一個點,用于進行直線繪制
mPath.quadTo(x1, y1, x2, y2) 生成二次貝塞爾曲線,(x1,y1) 為控制點,(x2,y2)為結束點
mPath.cubicTo(x1, y1, x2, y2, x3, y3) 生成三次貝塞爾曲線, (x1,y1) 為控制點,(x2,y2)為控制點,(x3,y3) 為結束點;即與二階區別多一個控制點
更多關于貝塞爾曲線的知識可以參考這篇文章:Android自定義View:Path之貝塞爾曲線
代碼示例
只要把思路理清楚了,代碼就比較簡單了,下面代碼是畫氣球和曲線的代碼:
canvas.drawBitmap(mBitmap, mLeft, 0, mPaint);
mEnd.x = mLeft + DisplayUtil.dip2px(getContext(),13);
mEnd.y = mBitmap.getHeight();
mControl.x = mEnd.x;
mControl.y = mStart.y - DisplayUtil.dip2px(getContext(),5);
mPath.reset();
mPath.moveTo(mStart.x, mStart.y);
mPath.quadTo(mControl.x, mControl.y, mEnd.x, mEnd.y);
canvas.drawPath(mPath, mPaint);
影片二
影片二效果
我們把第二個影片的效果也拆分出來:

其實這個影片相對簡單,途中總共有14個氣球,我們只要搞清楚每個氣球的軌跡,分別在各自的軌跡中繪制出來即可,
時差影片
這里面每個氣球不是同時啟動的,有的啟動早有的啟動晚,形成了一個時差效果,所以我們在設計這個影片的時候需要考慮每個氣球的啟動時間,每個氣球可以延遲不同的時間啟動,
面向物件繪制
要同時繪制14個氣球,每個氣球起點、終點、啟動時間等都不同,考慮到這些因素,我們必須以面向物件的思路來繪制,如果使用android做過一些小游戲的話,應該不難理解這個思路,比如做一個坦克大戰或者雷電游戲,每顆子彈的飛行軌跡也不一樣,我們也是把子彈設計成一個類,傳入起點、終點等屬性,讓子彈自己去完成繪制的,
下面是我抽象出來的氣球類:
private class Balloon {
Bitmap bitmap;
float endX;
float endY;
int delay;
void onDraw(Canvas canvas, int currTime, int width, int height) {
if (currTime < delay) {
return;
}
float startX = (width - bitmap.getWidth()) / 2;
float startY = height - bitmap.getHeight();
int duration = DURATION;
currTime = currTime - delay;
if (currTime > DURATION) {
currTime = DURATION;
}
float speedX = (endX - startX) / duration;
float speedY = (endY - startY) / duration;
float currX = startX + speedX * currTime;
float currY = startY + speedY * currTime;
canvas.drawBitmap(bitmap, currX, currY, null);
}
}
使用的時候初始化不同的氣球物件:
mBalloons = new ArrayList<>();
Balloon balloon1 = new Balloon();
balloon1.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.balloon_1);
balloon1.delay = 0;
balloon1.endX = 0;
balloon1.endY = DisplayUtil.dip2px(getContext(), 45);
mBalloons.add(balloon1);
Balloon balloon2 = new Balloon();
balloon2.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.balloon_2);
balloon2.delay = 50;
balloon2.endX = DisplayUtil.dip2px(getContext(),195);
balloon2.endY = DisplayUtil.dip2px(getContext(),67);
mBalloons.add(balloon2);
最侄訓制的時候,在view的onDraw方法中呼叫氣球的onDraw方法:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Balloon balloon : mBalloons) {
balloon.onDraw(canvas, mCurrTime, getWidth(), getHeight());
}
}
總結
作業中面對這樣的復雜影片,不要被嚇住,再復雜的影片我們拆分成一個個的小影片之后會發現自己其實是可以實作的,
完整代碼:GitHub地址,由于像這樣的影片往往不具有通用性,所以沒辦法做成一個庫來發布,感興趣的小伙伴版可以直接看原始碼,大家相互交流學習,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/159341.html
標籤:java
上一篇:Unity3D學習(二)
下一篇:Java語言實作石頭剪刀布游戲
