[Android]仿Periscope點贊效果,顯示愛心

先上效果圖,截屏看起來會卡頓,真機上效果不錯的


實現分爲兩步

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;




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章