先上效果圖,截屏看起來會卡頓,真機上效果不錯的
實現分爲兩步
1.在屏幕上顯示心形,動畫分別是透明度加縮放;
2.心形從下到上沿曲線滑行,實現貝塞爾曲線。
步驟一 顯示心形
1.加載心形圖片(需要自己準備心形圖片)
private Drawable[] mDrawables;
private Drawable mDrawableBlue, mDrawablePink, mDrawableGreen;
mDrawables = new Drawable[3];
mDrawableBlue = getResources().getDrawable(R.drawable.ic_heart_blue);
mDrawablePink = getResources().getDrawable(R.drawable.ic_heart_pink);
mDrawableGreen = getResources().getDrawable(R.drawable.ic_heart_green);
mDrawables[0] = mDrawableBlue;
mDrawables[1] = mDrawablePink;
mDrawables[2] = mDrawableGreen;
2.設置心形的位置,這裏選擇屏幕下方的中間位置(基於RelativeLayout)
private LayoutParams mDrawableLp;
<span style="white-space:pre"> </span>mDrawableLp = new LayoutParams(mDrawableWidth, mDrawableHeight);
mDrawableLp.addRule(RelativeLayout.CENTER_HORIZONTAL,
RelativeLayout.TRUE);
mDrawableLp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,
RelativeLayout.TRUE);
3.設置點擊按鈕的監聽時間,使用ImageView加載心形圖片
// 初始化心形
<span style="white-space:pre"> </span>private RelativeLayout mRelativeLayout;
ImageView heartImg = new ImageView(MainActivity.this);
heartImg.setImageDrawable(mDrawables[random.nextInt(3)]);
heartImg.setLayoutParams(mDrawableLp);
mRelativeLayout.addView(heartImg);
4.設置ImageView的縮放效果
// 設置縮放效果
ObjectAnimator alpha = ObjectAnimator.ofFloat(heartImg,.ALPHA, 0.2f, 1.0f);
ObjectAnimator scaleX = ObjectAnimator.ofFloat(heartImg,View.SCALE_X, 0.2f, 1.0f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(heartImg,View.SCALE_Y, 0.2f, 1.0f);
AnimatorSet set = new AnimatorSet();
<span style="white-space:pre"> </span>set.setDuration(300);
set.playTogether(alpha, scaleX, scaleY);
set.setInterpolator(new LinearInterpolator());
到這裏第一步的效果已經實現了,可以調用set.start()來觀看心形從無到有的效果。
步驟二 實現貝塞爾曲線動畫
首先簡單介紹一下貝塞爾曲線
P代表一個二維座標點,很容易可以對應到PointF,而t代表是目標運行的時間,取值[0,1]。
P0是起始點,P3是終點,而P1和P2是趨向點。大概可以理解爲一個正弦曲線的最高點和最低點。
1.使用插值器定義每一秒的目標的位置
初始化BezierEvaluator時將兩個中間點傳入
public class BezierEvaluator implements TypeEvaluator<PointF> {
private PointF mPointF1;
private PointF mPointF2;
public BezierEvaluator(PointF pointF1, PointF pointF2) {
this.mPointF1 = pointF1;
this.mPointF2 = pointF2;
}
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
float time = 1 - fraction;
PointF result = new PointF();// 結果
result.x = time * time * time * startValue.x + 3 * mPointF1.x * time
* time * fraction + 3 * mPointF2.x * fraction * fraction * time
+ endValue.x * fraction * fraction * fraction;
result.y = time * time * time * startValue.y + 3 * mPointF1.y * time
* time * fraction + 3 * mPointF2.y * fraction * fraction * time
+ endValue.y * fraction * fraction * fraction;
return result;
}
}
2.將插值器插入到動畫中
初始化ValueAnimator時將起點和終點的值傳入
<span style="white-space:pre"> </span>// 貝塞爾曲線效果
BezierEvaluator bezierEvaluator = new BezierEvaluator(getPointf(2), getPointf(1));
ValueAnimator va = ValueAnimator.ofObject(bezierEvaluator,new PointF((mScreenWidth - mDrawableWidth) / 2,
mScreenHeight - mDrawableHeight), new PointF(random.nextInt(mScreenWidth), 0));
va.addUpdateListener(new UpdateListener(heartImg));
va.setTarget(heartImg);
va.setDuration(2000);
3.增加動畫更新監聽器,否則並無卵用
private class UpdateListener implements AnimatorUpdateListener {
View target;
public UpdateListener(View target) {
this.target = target;
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointf = (PointF) animation.getAnimatedValue();
target.setX(pointf.x);
target.setY(pointf.y);
target.setAlpha(1 - animation.getAnimatedFraction());
}
}
4.將兩個動畫合併在一起
<span style="white-space:pre"> </span>// 拼合兩種動畫
AnimatorSet finalSet = new AnimatorSet();
finalSet.playSequentially(set);
finalSet.playSequentially(set, va);
finalSet.addListener(new HeartAnimatorlistener(heartImg));
finalSet.start();
5.動畫的監聽
移除ImageView,否則Imageview會只增不減
private class HeartAnimatorlistener implements AnimatorListener {
private View target;
public HeartAnimatorlistener(View target) {
this.target = target;
}
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mRelativeLayout.removeView(target);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
}
補充:獲取屏幕的寬高,用於確定心形的起點
<span style="white-space:pre"> </span>// 獲取屏幕寬高
DisplayMetrics dm = getResources().getDisplayMetrics();
mScreenWidth = dm.widthPixels;
mScreenHeight = dm.heightPixels;