前幾天 Ui 突然給我一個(gè) gif 圖說要把這個(gè)做成啟動動畫,看到效果圖的我表示一臉懵逼绿语。
好吧秃症,懵逼歸懵逼,效果還是要做出來吕粹,作為一只沒怎么寫過動效的猿种柑,第一反應(yīng)就是讓 Ui 做成 gif 圖,然后 Ios 的哥們說 gif 圖內(nèi)存大匹耕,容易失真聚请,我們都已經(jīng)用貝塞爾曲線做出來了(Ios 比我們 android 先跑半個(gè)版本)。好吧稳其,那就手?jǐn)]動效吧驶赏,寶寶不哭炸卑。
首先對著 gif 圖一幀一幀觀察了一遍,分析動畫的過程煤傍。把動畫拆解成兩部分矾兜。
1、四個(gè)顏色的圓運(yùn)動患久。
2椅寺、Logo的出現(xiàn)
logo 的出現(xiàn)就是簡單的alpha 動畫,難點(diǎn)就在四個(gè)圓運(yùn)動蒋失。
找 Ui 拿到了四個(gè)圓的運(yùn)動軌跡返帕,如下圖所示:
根據(jù)軌跡,我把運(yùn)動軌跡拆分成平移和半圓旋轉(zhuǎn)篙挽,創(chuàng)建出Path路徑荆萤,再讓圓沿著 Path 運(yùn)動,在運(yùn)動的時(shí)候加上 alpha 和縮放的屬性铣卡,結(jié)束的時(shí)候把圓移除掉并顯示 logo 就好链韭。
分析結(jié)束,接下來就上代碼:
第一步:創(chuàng)建 LauncherView 繼承 RelativeLayout煮落,在構(gòu)造方法里面 init()添加四個(gè)顏色的圓
private void init(){
LayoutParamslp=newLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
lp.addRule(CENTER_HORIZONTAL,TRUE);//這里的TRUE 要注意 不是true
lp.addRule(CENTER_VERTICAL,TRUE);
lp.setMargins(0,0,0,dp80);
purple=newImageView(getContext());
purple.setLayoutParams(lp);
purple.setImageDrawable(getResources().getDrawable(R.drawable.shape_circle_purple));
addView(purple);
yellow=newImageView(getContext());
yellow.setLayoutParams(lp);
yellow.setImageDrawable(getResources().getDrawable(R.drawable.shape_circle_yellow));
addView(yellow);
blue=newImageView(getContext());
blue.setLayoutParams(lp);
blue.setImageDrawable(getResources().getDrawable(R.drawable.shape_circle_blue));
addView(blue);
red=newImageView(getContext());
red.setLayoutParams(lp);
red.setImageDrawable(getResources().getDrawable(R.drawable.shape_circle_red));
addView(red);
}
ObjectAnimator動畫原理
ObjectAnimator.ofObject(….,”xxx”,估值值,區(qū)間數(shù)組); 【定義動畫屬性xxx和區(qū)間】
插值器/加速器(Interpolator)【返回當(dāng)前數(shù)字進(jìn)度t】
估值值(Evaluator)【根當(dāng)前數(shù)字進(jìn)度計(jì)算并返回當(dāng)前值】
調(diào)用setXxx函數(shù) 【根據(jù)封裝好的setXxx函數(shù)并反射調(diào)用敞峭,將第三步返回當(dāng)前值以參數(shù)傳入】
繪制四個(gè)圓圈的 Path,這里以紅色圓圈為例蝉仇,三階貝塞爾曲線描點(diǎn)不會的話旋讹,可以參考 Ui 的設(shè)計(jì)路徑描點(diǎn),Ps 的鋼筆工具就是貝塞爾曲線轿衔。
ViewPathredPath1=newViewPath();//偏移坐標(biāo)
redPath1.moveTo(0,0);
redPath1.lineTo(mWidth/5-mWidth/2,0);
ViewPathredPath2=newViewPath();
redPath2.moveTo(mWidth/5-mWidth/2,0);
redPath2.curveTo(-700,-mHeight/2,mWidth/3*2,-mHeight/3*2,0,-dp80);
setAnimation(red,redPath1,redPath2);
接下來將 Path 轉(zhuǎn)換成 ObjectAnimation
private void setAnimation(final ImageView target,ViewPath path1,ViewPath path2){
//左右平移
ObjectAnimator redAnim1=ObjectAnimator.ofObject(newViewObj(target),"fabLoc",newViewPathEvaluator(),path1.getPoints().toArray());
redAnim1.setInterpolator(newAccelerateDecelerateInterpolator());
redAnim1.setDuration(800);
//貝塞爾曲線
ObjectAnimator redAnim2=ObjectAnimator.ofObject(newViewObj(target),"fabLoc",newViewPathEvaluator(),path2.getPoints().toArray());
redAnim2.setInterpolator(newAccelerateDecelerateInterpolator());
//組合動畫
addAnimation(redAnim1,redAnim2,target);
}
然后組合動畫得到一個(gè)圓的完整運(yùn)行軌跡沉迹。
private void addAnimation(ObjectAnimatoranimator1,ObjectAnimatoranimator2,ImageViewtarget){
ObjectAnimator alpha=ObjectAnimator.ofFloat(target,View.ALPHA,1f,0.5f);
ObjectAnimator scaleX=ObjectAnimator.ofFloat(target,View.SCALE_X,1,getScale(target),1.0f);
ObjectAnimator scaleY=ObjectAnimator.ofFloat(target,View.SCALE_Y,1,getScale(target),1.0f);
AnimatorSet all2=newAnimatorSet();
all2.setDuration(1800);
all2.playTogether(alpha,scaleX,scaleY,animator2);
all2.addListener(newAnimEndListener(target));
AnimatorSetall=newAnimatorSet();
all.playSequentially(animator1,all2);
all.start();
}
最后,顯示 logo 動畫
private void showLogo(){
Viewview=View.inflate(getContext(),R.layout.widget_load_view,this);
Viewlogo=view.findViewById(R.id.iv_logo);
finalViewslogo=view.findViewById(R.id.iv_slogo);
ObjectAnimatoralpha=ObjectAnimator.ofFloat(logo,View.ALPHA,0f,1f);
alpha.setDuration(800);
alpha.start();
newHandler().postDelayed(newRunnable(){
@Override
public voidrun(){
ObjectAnimator alpha=ObjectAnimator.ofFloat(slogo,View.ALPHA,0f,1f);
alpha.setDuration(200);
alpha.start();
}
},400);
}
好害驹,到這里鞭呕,炫酷的啟動頁動畫已經(jīng)擼出來了,就是一個(gè)簡單的ObjectAnimator使用宛官,大家不要被自定義 view 這個(gè)紙老虎嚇到葫松。