1、前言
本文github地址:https://github.com/qike2015/SignUpAnimation
在網(wǎng)站上看到一個很絢麗的注冊設計,先看下原設計效果:

下面是我實現(xiàn)的效果:

本文講解如何通過屬性動畫實現(xiàn)該效果。
動畫分析
整個動畫流程分成下面三部分來單獨實現(xiàn):
- 注冊按鈕點擊后的擴散動畫
- 網(wǎng)絡請求動畫
- 主頁面動畫
擴散動畫:當用戶點擊注冊按鈕后,整個按鈕呈圓形擴散直至鋪滿整個屏幕。
網(wǎng)絡請求動畫可以分為以下幾個部分:
-
signUp文字入場動畫:文字從下往上平移,同時播放縮放動畫,并且透明度逐漸加深。 - 白線延長動畫,線條向右延伸,
-
success文字入場動畫,同時伴隨sign up文字的出場動畫,由左往右移動與sign up碰撞后減速停止,sign up向右移動并消失,倆個文字透明度皆發(fā)生變化。
請求網(wǎng)絡動畫播放成功后跳轉(zhuǎn)到主頁面,主頁的Tab欄由鋪滿整個屏幕逐漸變小到原始高度,并且Tab欄的倆個菜單按鈕透明度也發(fā)生變化。
2、注冊按鈕后的擴散動畫
點擊注冊按鈕后,顯示動畫播放view,開始播放縮放動畫。
整個縮放動畫就是一個圓形的view的放大動畫,將該view的背景設置為shape即可實現(xiàn)圓形效果。
圓形view的背景代碼:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="180dp"/>
<solid android:color="@color/colorPrimary"/>
</shape>
擴散動畫代碼:
public static void spreadAni(View target, float endScale, SimpleAnimatorListener endListener)
{
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(target, "ScaleX", endScale);
scaleXAnimator.setInterpolator(new AccelerateInterpolator());
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(target, "ScaleY", endScale);
scaleYAnimator.setInterpolator(new AccelerateInterpolator());
AnimatorSet animSet = new AnimatorSet();
animSet.play(scaleXAnimator).with(scaleYAnimator);
animSet.setDuration(500);
animSet.start();
animSet.addListener(endListener);
}
整個擴散(放大)動畫分成倆個屬性動畫,分別播放view在x方向和y方向的縮放動畫,該動畫最重要的地方在于計算最終放大比例,因為我們在布局文件中,縮放view的位置并沒有在整個動畫的正中間,還是向上偏移了一點,所以最終縮放值在計算結(jié)果的基礎上加1,否則動畫結(jié)束后背景顏色無法鋪滿整個屏幕:
//計算擴散動畫最終放大比例
private float getScale()
{
//原始擴散圓的直徑
int orgWidth = v_spread.getMeasuredWidth();
int width = getMeasuredWidth();
int height = getMeasuredHeight();
//擴散圓最終擴散的圓的半徑
float finalDiameter = (int) (Math.sqrt(width * width + height * height));
//因為圓未居中,所以加1
return finalDiameter / orgWidth + 1;
}
3、網(wǎng)絡請求動畫
擴散動畫播放結(jié)束后開始播放網(wǎng)絡請求動畫。整個過程分成三部分,下面分別講解實現(xiàn)方法。
3.1 signUp入場動畫文字
擴散動畫后結(jié)束后緊接著播放singUp的入場動畫,給動畫設置監(jiān)聽,在監(jiān)聽的onAnimationEnd(Animator animation)中開始入場動畫。
入場動畫代碼:
/**
* sign up文字入場動畫
*
* @param target 需要播放動畫的view
* @param endListener 動畫監(jiān)聽
*/
public static void signUpTextInAni(View target, SimpleAnimatorListener endListener)
{
target.setVisibility(View.VISIBLE);
int targetHeight = target.getMeasuredHeightAndState();
ObjectAnimator scaleX = ObjectAnimator.ofFloat(target, "ScaleX", 0.75f, 0.87f, 1f, 1.1f, 1.0f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(target, "ScaleY", 0.75f, 0.87f, 1f, 1.1f, 1.0f);
ObjectAnimator translationAni = ObjectAnimator.ofFloat(target, "TranslationY", targetHeight * 0.8f, -targetHeight * 0.2f, 0);
ObjectAnimator alphaAni = ObjectAnimator.ofFloat(target, "Alpha", 0.5f, 1.0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(scaleX, scaleY, translationAni, alphaAni);
animatorSet.setDuration(2000);
animatorSet.start();
animatorSet.addListener(endListener);
}
動畫開始播放時,將signUp文字(簡稱注冊文字,下同)顯示,通過AnimatorSet的playTogether()方法同上開啟四格動畫,即注冊文字的縮放動畫(x、y方向)、Y方向的平移動畫,透明度提升動畫。其中,縮放動畫從0.75倍放大到1.1倍大小后再縮放回原始大小(1.0倍),這樣實現(xiàn)一個放大膨脹然后再輕微反彈縮小到原始大小的效果。平移動畫類似,上升后再反彈下沉一定高度。具體變化值詳見代碼。
3.2 白線延長動畫
注冊文字入場動畫播放動畫結(jié)束后開始白色線條的延長動畫。這個動畫就是線條在X方向的縮放:
public static void lineExpendAni(View target, SimpleAnimatorListener endListener)
{
target.setVisibility(View.VISIBLE);
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "ScaleX", 0, 0.6f, 0.9f, 1.0f);
animator.setDuration(1500);
animator.setInterpolator(new DecelerateInterpolator());
target.setPivotX(0);
animator.start();
animator.addListener(endListener);
}
利用setPivotX(0)方法把線條X方向的中心點(可理解為縮放的起始點,動畫將以該坐標為中線開始輻射,默認為view的中線點)設置0,這樣擴大動畫只會向一個方向發(fā)生,即可實現(xiàn)線條延長效果。動畫播放數(shù)值"0, 0.6f, 0.9f, 1.0f"并不是等差排列,還是越來越小,這樣即可實現(xiàn)減速效果(根據(jù)差值的縮小梯度絕對減速度的變化值)。
3.3 success文字入場動畫
public static void successInAni(View success, View signUpView, SimpleAnimatorListener endListener)
{
success.setVisibility(View.VISIBLE);
int durationTime = 1000;
int width = success.getMeasuredWidth();
ObjectAnimator successTranslationAni = ObjectAnimator.ofFloat(success, "TranslationX", width * -1.2f, width * -0.2f, 0);
ObjectAnimator successAlphaAni = ObjectAnimator.ofFloat(success, "Alpha", 0.1f, 1.0f, 1.0f);
ObjectAnimator signUpTranslationAni = ObjectAnimator.ofFloat(signUpView, "TranslationX", 0, width * 0.75f, width * 1.5f);
signUpTranslationAni.setInterpolator(new AccelerateInterpolator());
ObjectAnimator signUpAlphaAni = ObjectAnimator.ofFloat(signUpView, "Alpha", 1.0f, 1.0f, 0.4f, 0.0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(successTranslationAni, successAlphaAni, signUpTranslationAni, signUpAlphaAni);
animatorSet.setDuration(durationTime);
animatorSet.start();
animatorSet.addListener(endListener);
}
success文字(成功文字)的入場動畫包含倆組動畫:
- 成功文字入場
- 注冊文字出場
倆組動畫相互對應,即X方向的平移和透明度的增減。動畫的播放值代碼寫得很清楚,這里就不在累贅復述了。
4、主頁動畫
我們可動畫播放view設置一個自定義監(jiān)聽事件,當成功文字播放完成后,回調(diào)給activity。當動畫結(jié)束后,跳轉(zhuǎn)到主頁面。
主頁顯示后,播放動畫,動畫包含倆個動畫,先看代碼:
{
ValueAnimator valueAnimator = ValueAnimator.ofInt(rl_title.getHeight(), DensityUtils.dp2px(this, 50));
valueAnimator.setInterpolator(new AccelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
rl_title.getLayoutParams().height = (int) animation.getAnimatedValue();
rl_title.requestLayout();
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(valueAnimator,
ObjectAnimator.ofFloat(iv_me, "Alpha", 0.1f, 1.0f),
ObjectAnimator.ofFloat(iv_menu, "Alpha", 0.1f, 1.0f));
animatorSet.setDuration(1200);
animatorSet.start();
}
代碼中:我們利用一個ValueAnimator實現(xiàn)tabView(rl_title)的高度收縮動畫,rl_title的起始高度鋪滿整個屏幕,最后高度變?yōu)?0dp收縮到屏幕頂部,同時倆個按鈕 iv_me 、iv_menu透明度加深。
給ValueAnimator通過addUpdateListener設置一個數(shù)值變化監(jiān)聽,根據(jù)動畫計算的當前值通過布局參數(shù)動態(tài)設置rl_title的高度。
5、結(jié)束
最后奉上源碼下載地址:http://download.csdn.net/detail/q649381130/9621869