前言:剛開始是假裝堅(jiān)強(qiáng),后來就真的堅(jiān)強(qiáng)了。——楊絳。
承接上一篇自定義 View 屬性動(dòng)畫,本篇實(shí)現(xiàn)一個(gè)類似“小球”撞擊效果,可以作為數(shù)據(jù)加載頁面來使用。其實(shí)這個(gè)效果在某些 App 里面看到過,只不過忘記在哪看到的了。
好了,先看一下實(shí)現(xiàn)效果圖:

看到這種效果,就像是真空中的小球一直在發(fā)生碰撞一樣,這種方式該如何去做呢?其實(shí)有很多種方式去實(shí)現(xiàn),但是最簡單的方式還是使用屬性動(dòng)畫來實(shí)現(xiàn):
使用屬性動(dòng)畫實(shí)現(xiàn)應(yīng)該有最基本的四步:
- 1)、繪制圓形小球
- 2)、讓圓形小球動(dòng)起來
- 3)、根據(jù)三個(gè)圓形的變化規(guī)律,改變小球顏色
- 4)、優(yōu)化
1、繪制圓球
對于小球,也有不同的方式去繪制??梢灾苯赢嬕粋€(gè) shape 圖形,也可以自定義 View 進(jìn)行繪制,這里選用后者,因?yàn)楹笳呦鄬`活一點(diǎn)。
自定義 View 進(jìn)行繪制圓形:
public class CircularView extends View {
private int Color;
private Paint mPaint;
public void setColor(int color) {
this.Color = color;
mPaint.setColor(Color);
invalidate();
}
public int getColor() {
return Color;
}
public CircularView(Context context) {
this(context,null);
}
public CircularView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CircularView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float cx = getWidth()/2;
canvas.drawCircle(cx,cx,cx,mPaint);
}
}
在 OnDraw 中,直接使用 canvas 畫了一個(gè)圓,然后提供 setColor 方法,并重繪。這樣就能實(shí)現(xiàn)創(chuàng)建任意顏色的小圓了。
public class LoadingView extends RelativeLayout {
private CircularView mLeftCircularView;
private CircularView mCenterCircularView;
private CircularView mRightCircularView;
public LoadingView(Context context) {
this(context,null);
}
public LoadingView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mLeftCircularView = createCircularView(context);
mLeftCircularView.setColor(Color.RED);
mRightCircularView = createCircularView(context);
mRightCircularView.setColor(Color.BLUE);
mCenterCircularView = createCircularView(context);
mCenterCircularView.setColor(Color.GREEN);
addView(mLeftCircularView);
addView(mRightCircularView);
//后添加在上面,表示中間的小圓
addView(mCenterCircularView);
/**--------- 開啟動(dòng)畫 ---------**/
post(new Runnable() {
@Override
public void run() {
startOutAnimation();
}
});
}
/**
* 開啟往外移動(dòng)的動(dòng)畫
*/
private void startOutAnimation() {
//左邊小圓左移動(dòng)畫
ObjectAnimator outObjectAnimator = ObjectAnimator.ofFloat();
//右邊小圓右移動(dòng)畫
}
/**
* 開啟往內(nèi)移動(dòng)的動(dòng)畫
*/
private void startInnerAnimation() {
}
/**
* 統(tǒng)一創(chuàng)建小圓
* @param context
* @return
*/
private CircularView createCircularView(Context context) {
CircularView circularView = new CircularView(context);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(dip2px(10),dip2px(10));
params.addRule(CENTER_IN_PARENT);
circularView.setLayoutParams(params);
return circularView;
}
private int dip2px(int dip) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dip,getResources().getDisplayMetrics());
}
}
這里創(chuàng)建一個(gè) LoadingView 繼承自 RelativeLayout,當(dāng)然繼承自 FrameLayout 也是可以的。
在初識(shí)化的時(shí)候,創(chuàng)建了三個(gè) CircularView 設(shè)置其顏色并添加到 LoadingView 中,注意由于繼承了 RelativeLayout,所以添加順序是有講究的,中間的小圓讓它在最上面,左右小圓在下面。此時(shí)運(yùn)行程序:

注意上面三個(gè)小球是重疊起來的。
2、讓圓形小球動(dòng)起來
該節(jié)內(nèi)容就是使用屬性動(dòng)畫讓小圓球進(jìn)行移動(dòng)了。
還是先看代碼:
/**
* 開啟往外移動(dòng)的動(dòng)畫
*/
private void startOutAnimation() {
//左邊小圓左移動(dòng)畫
ObjectAnimator outLeftObjectAnimator = ObjectAnimator.ofFloat(mLeftCircularView,"TranslationX",0f,-translationDis);
//右邊小圓右移動(dòng)畫
ObjectAnimator outRightObjectAnimator = ObjectAnimator.ofFloat(mRightCircularView,"TranslationX",0f,translationDis);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(DURATION);
animatorSet.setInterpolator(new DecelerateInterpolator(2f));
animatorSet.playTogether(outLeftObjectAnimator,outRightObjectAnimator);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//動(dòng)畫結(jié)束,開啟往內(nèi)移動(dòng)的動(dòng)畫
startInnerAnimation();
}
});
animatorSet.start();
}
/**
* 開啟往內(nèi)移動(dòng)的動(dòng)畫
*/
private void startInnerAnimation() {
//左邊小圓右移動(dòng)畫
ObjectAnimator innerLeftObjectAnimator = ObjectAnimator.ofFloat(mLeftCircularView,"TranslationX",-translationDis,0f);
//右邊小圓左移動(dòng)畫
ObjectAnimator innerRightObjectAnimator = ObjectAnimator.ofFloat(mRightCircularView,"TranslationX",translationDis,0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(DURATION);
animatorSet.setInterpolator(new AccelerateInterpolator());
animatorSet.playTogether(innerLeftObjectAnimator,innerRightObjectAnimator);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//動(dòng)畫結(jié)束,開啟往內(nèi)移動(dòng)的動(dòng)畫
startOutAnimation();
}
});
animatorSet.start();
}
發(fā)現(xiàn)是左邊小圓往左側(cè)移動(dòng),中間小圓不變化,右邊小圓往右移動(dòng)。都是屬性動(dòng)畫最基本的用法,而且上一篇也做了很詳細(xì)的解釋,這里應(yīng)該沒問任何問題。運(yùn)行程序:

此時(shí)已經(jīng)完成了小球動(dòng)態(tài)改變效果,但是在回彈的時(shí)候是需要改變小球顏色的。
3、4、改變小球的顏色,最后的優(yōu)化
1、改變小球顏色
看一下文章開頭,改變規(guī)律如下:
左邊小球顏色—>中間小球顏色—>右邊小球顏色—>左邊小球顏色
按照上面這個(gè)規(guī)律代碼如下:
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//動(dòng)畫結(jié)束,開啟往外移動(dòng)的動(dòng)畫
startOutAnimation();
//改變小球顏色
//左邊小球顏色—>中間小球顏色—>右邊小球顏色—>左邊小球顏色
int mLeftCircularViewColor = mLeftCircularView.getColor();
int mCenterCircularViewColor = mCenterCircularView.getColor();
int mRightCircularViewColor = mRightCircularView.getColor();
mCenterCircularView.setColor(mLeftCircularViewColor);
mRightCircularView.setColor(mCenterCircularViewColor);
mLeftCircularView.setColor(mRightCircularViewColor);
}
});
監(jiān)聽在 startInnerAnimation,也即動(dòng)畫內(nèi)移結(jié)束的時(shí)候開始改變球的顏色。
2、一點(diǎn)點(diǎn)優(yōu)化
這里內(nèi)容跟上文是一樣的,直接把代碼貼在下面了:

運(yùn)行程序:

最后呈現(xiàn)一張動(dòng)圖送給你們
