英文: Twitter’s like animation in Android - alternative
相關動畫網址:http://frogermcs.github.io/twitters-like-animation-in-android-alternative/,
更多動畫網址:http://frogermcs.github.io/
作者來源:Miroslaw Stanek
小編自己遇到的問題:最近在研究一個Twitter的like動畫安卓版,在任何手機上面都可以正常播放動畫,只有在一個htc的手機上面,沒有任何錯誤日誌,動畫播放不出來
操作:設置–》開發者選擇–》高級選項–》動畫,把動畫的選項打開就好了。
不久前Twitter展示了具有現代感的心形動畫-作爲star圖標的替代。
雖然實現這個動畫最簡單的方法是使用 Frame Animation ,但是我們嘗試用更靈活的方法來實現-手動繪製並用屬性動畫。這篇文章只是概要,沒有深入的技術細節
一:實現
我們將創建一個名叫LikeButtonView的view,它是一個由三個子view構成的FrameLayout- CircleView 顯示星星圖標下面的圓,ImageView (星星)以及代表按鈕周圍浮點的DotsView 。
CircleView
這個視圖負責繪製星星圖標下面的大圓。它本可以實現得更簡單(通過xml ),但是這裏我們應該考慮按鈕下面的背景顏色。
我們在canvas上繪製圓的實現:
Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
tempCanvas.drawColor(0xffffff, PorterDuff.Mode.CLEAR);
tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, outerCircleRadiusProgress * maxCircleSize, circlePaint);
tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, innerCircleRadiusProgress * maxCircleSize, maskPaint);
canvas.drawBitmap(tempBitmap, 0, 0, null);
}
先使用CLEAR 模式繪製顏色以清除canvas。然後根據給定的進度(各自的進度是獨立的)繪製內外圓。
內圓使用這樣定義的mask paint :
Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
maxCircleSize = w / 2;
tempBitmap = Bitmap.createBitmap(getWidth(), getWidth(), Bitmap.Config.ARGB_8888);
tempCanvas = new Canvas(tempBitmap);
}
我們需要完全透明,不然的話內圓就會顯示窗口顏色。
對於那些眼睛機靈的人應該還注意到了另外一件事-我們的外圓顏色是基於當前進度而變化的。這是通過 ArgbEvaluator 類來完成,該類可以基於一個給定的因子在兩個顏色之間變換:
private void updateCircleColor() {
float colorProgress = (float) Utils.clamp(outerCircleRadiusProgress, 0.5, 1);
colorProgress = (float) Utils.mapValueFromRangeToRange(colorProgress, 0.5f, 1f, 0f, 1f);
this.circlePaint.setColor((Integer) argbEvaluator.evaluate(colorProgress, START_COLOR, END_COLOR));
}
三:DotsView
這個view將繪製浮動在星星圖標周圍的圓點。跟CircleView一樣,它是使用onDraw()來做這件事的:
protected void onDraw(Canvas canvas) {
drawOuterDotsFrame(canvas);
drawInnerDotsFrame(canvas);
}
private void drawOuterDotsFrame(Canvas canvas) {
for (int i = 0; i < DOTS_COUNT; i++) {
int cX = (int) (centerX + currentRadius1 * Math.cos(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
int cY = (int) (centerY + currentRadius1 * Math.sin(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
canvas.drawCircle(cX, cY, currentDotSize1, circlePaints[i % circlePaints.length]);
}
}
private void drawInnerDotsFrame(Canvas canvas) {
for (int i = 0; i < DOTS_COUNT; i++) {
int cX = (int) (centerX + currentRadius2 * Math.cos((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
int cY = (int) (centerY + currentRadius2 * Math.sin((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
canvas.drawCircle(cX, cY, currentDotSize2, circlePaints[(i + 1) % circlePaints.length]);
}
}
圓點是基於currentProgress繪製的,背後是數學邏輯,老實說從安卓sdk的角度來看這裏沒有什麼有趣的地方,倒是有兩個跟數學相關的東西:
圓點分佈在一個圓上-它們的位置決定於:
int cX = (int) (centerX + currentRadius1 * Math.cos(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
int cY = (int) (centerY + currentRadius1 * Math.sin(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
意味着:在每個 OUTER_DOTS_POSITION_ANGLE 上設置圓點 (51 度).
每個圓點都有它自己的顏色動畫:
private void updateDotsPaints() {
if (currentProgress < 0.5f) {
float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0f, 0.5f, 0, 1f);
circlePaints[0].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_1, COLOR_2));
circlePaints[1].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_2, COLOR_3));
circlePaints[2].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_3, COLOR_4));
circlePaints[3].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_4, COLOR_1));
} else {
float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.5f, 1f, 0, 1f);
circlePaints[0].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_2, COLOR_3));
circlePaints[1].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_3, COLOR_4));
circlePaints[2].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_4, COLOR_1));
circlePaints[3].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_1, COLOR_2));
}
}
這意味着圓點顏色在3個區間形式的值之間動畫。我們再一次使用ArgbEvaluator 讓它平滑。其餘就很簡單了
CircleView完整代碼
package com.loveta.umengexample;
import android.animation.ArgbEvaluator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Property;
import android.view.View;
/**
* Created by Miroslaw Stanek on 21.12.2015.
*/
public class CircleView extends View {
private static final int START_COLOR = 0xFFFF5722;
private static final int END_COLOR = 0xFFFFC107;
private ArgbEvaluator argbEvaluator = new ArgbEvaluator();
private Paint circlePaint = new Paint();
private Paint maskPaint = new Paint();
private Bitmap tempBitmap;
private Canvas tempCanvas;
private float outerCircleRadiusProgress = 0f;
private float innerCircleRadiusProgress = 0f;
private int maxCircleSize;
public CircleView(Context context) {
super(context);
init();
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
// Log.e("==tjj", "============");
circlePaint.setStyle(Paint.Style.FILL);//實心園
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//PorterDuff.Mode.CLEAR---所繪製不會提交到畫布上。http://blog.csdn.net/edisonlg/article/details/7084977
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
maxCircleSize = w / 2;
tempBitmap = Bitmap.createBitmap(getWidth(), getWidth(), Bitmap.Config.ARGB_8888);
tempCanvas = new Canvas(tempBitmap);
}
@Override
protected void onDraw(Canvas canvas) {//視圖負責繪製星星圖標下面的大圓
super.onDraw(canvas);
Log.e("==========tan111===", "tan111");
tempCanvas.drawColor(0xffffff, PorterDuff.Mode.CLEAR);//設置畫布的背景顏色
tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, outerCircleRadiusProgress * maxCircleSize, circlePaint);
tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, innerCircleRadiusProgress * maxCircleSize, maskPaint);
canvas.drawBitmap(tempBitmap, 0, 0, null);
}
public void setInnerCircleRadiusProgress(float innerCircleRadiusProgress) {
this.innerCircleRadiusProgress = innerCircleRadiusProgress;
// Log.e("==========tan===", "tan");
postInvalidate();
// invalidate();
}
public float getInnerCircleRadiusProgress() {
return innerCircleRadiusProgress;
}
public void setOuterCircleRadiusProgress(float outerCircleRadiusProgress) {
this.outerCircleRadiusProgress = outerCircleRadiusProgress;
updateCircleColor();
postInvalidate();
// invalidate();
}
private void updateCircleColor() {
float colorProgress = (float) Utils.clamp(outerCircleRadiusProgress, 0.5, 1);
colorProgress = (float) Utils.mapValueFromRangeToRange(colorProgress, 0.5f, 1f, 0f, 1f);
this.circlePaint.setColor((Integer) argbEvaluator.evaluate(colorProgress, START_COLOR, END_COLOR));
}
public float getOuterCircleRadiusProgress() {
return outerCircleRadiusProgress;
}
public static final Property<CircleView, Float> INNER_CIRCLE_RADIUS_PROGRESS =
new Property<CircleView, Float>(Float.class, "innerCircleRadiusProgress") {
@Override
public Float get(CircleView object) {
return object.getInnerCircleRadiusProgress();
}
@Override
public void set(CircleView object, Float value) {
// Log.e("==================tjj===","INNER_CIRCLE_RADIUS_PROGRESS");
object.setInnerCircleRadiusProgress(value);
}
};
public static final Property<CircleView, Float> OUTER_CIRCLE_RADIUS_PROGRESS =
new Property<CircleView, Float>(Float.class, "outerCircleRadiusProgress") {
@Override
public Float get(CircleView object) {
return object.getOuterCircleRadiusProgress();
}
@Override
public void set(CircleView object, Float value) {
object.setOuterCircleRadiusProgress(value);
}
};
}
DotsView完整代碼
package com.loveta.umengexample;
import android.animation.ArgbEvaluator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Property;
import android.view.View;
/**
* Created by Miroslaw Stanek on 20.12.2015.
*/
public class DotsView extends View {
private static final int DOTS_COUNT = 7;
private static final int OUTER_DOTS_POSITION_ANGLE = 360 / DOTS_COUNT;
private static final int COLOR_1 = 0xFFFFC107;
private static final int COLOR_2 = 0xFFFF9800;
private static final int COLOR_3 = 0xFFFF5722;
private static final int COLOR_4 = 0xFFF44336;
private final Paint[] circlePaints = new Paint[4];
private int centerX;
private int centerY;
private float maxOuterDotsRadius;
private float maxInnerDotsRadius;
private float maxDotSize;
private float currentProgress = 0;
private float currentRadius1 = 0;
private float currentDotSize1 = 0;
private float currentDotSize2 = 0;
private float currentRadius2 = 0;
private ArgbEvaluator argbEvaluator = new ArgbEvaluator();
public DotsView(Context context) {
super(context);
init();
}
public DotsView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DotsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public DotsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
for (int i = 0; i < circlePaints.length; i++) {
circlePaints[i] = new Paint();
circlePaints[i].setStyle(Paint.Style.FILL);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerX = w / 2;
centerY = h / 2;
maxDotSize = 20;
maxOuterDotsRadius = w / 2 - maxDotSize * 2;
maxInnerDotsRadius = 0.8f * maxOuterDotsRadius;
}
@Override
protected void onDraw(Canvas canvas) {//繪製浮動在星星圖標周圍的圓點
drawOuterDotsFrame(canvas);
drawInnerDotsFrame(canvas);
}
private void drawOuterDotsFrame(Canvas canvas) {
for (int i = 0; i < DOTS_COUNT; i++) {
int cX = (int) (centerX + currentRadius1 * Math.cos(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
int cY = (int) (centerY + currentRadius1 * Math.sin(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
canvas.drawCircle(cX, cY, currentDotSize1, circlePaints[i % circlePaints.length]);
}
}
private void drawInnerDotsFrame(Canvas canvas) {
for (int i = 0; i < DOTS_COUNT; i++) {
int cX = (int) (centerX + currentRadius2 * Math.cos((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
int cY = (int) (centerY + currentRadius2 * Math.sin((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
canvas.drawCircle(cX, cY, currentDotSize2, circlePaints[(i + 1) % circlePaints.length]);
}
}
public void setCurrentProgress(float currentProgress) {
this.currentProgress = currentProgress;
updateInnerDotsPosition();//1
updateOuterDotsPosition();//2
updateDotsPaints();//3
updateDotsAlpha();//4
postInvalidate();//1
}
public float getCurrentProgress() {
return currentProgress;
}
private void updateInnerDotsPosition() {
if (currentProgress < 0.3f) {
this.currentRadius2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0, 0.3f, 0.f, maxInnerDotsRadius);
} else {
this.currentRadius2 = maxInnerDotsRadius;
}
if (currentProgress < 0.2) {
this.currentDotSize2 = maxDotSize;
} else if (currentProgress < 0.5) {
this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.2f, 0.5f, maxDotSize, 0.3 * maxDotSize);
} else {
this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.5f, 1f, maxDotSize * 0.3f, 0);
}
}
private void updateOuterDotsPosition() {
if (currentProgress < 0.3f) {
this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.0f, 0.3f, 0, maxOuterDotsRadius * 0.8f);
} else {
this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.3f, 1f, 0.8f * maxOuterDotsRadius, maxOuterDotsRadius);
}
if (currentProgress < 0.7) {
this.currentDotSize1 = maxDotSize;
} else {
this.currentDotSize1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.7f, 1f, maxDotSize, 0);
}
}
private void updateDotsPaints() {
if (currentProgress < 0.5f) {
float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0f, 0.5f, 0, 1f);
circlePaints[0].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_1, COLOR_2));
circlePaints[1].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_2, COLOR_3));
circlePaints[2].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_3, COLOR_4));
circlePaints[3].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_4, COLOR_1));
} else {
float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.5f, 1f, 0, 1f);
circlePaints[0].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_2, COLOR_3));
circlePaints[1].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_3, COLOR_4));
circlePaints[2].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_4, COLOR_1));
circlePaints[3].setColor((Integer) argbEvaluator.evaluate(progress, COLOR_1, COLOR_2));
}
}
private void updateDotsAlpha() {
float progress = (float) Utils.clamp(currentProgress, 0.6f, 1f);
int alpha = (int) Utils.mapValueFromRangeToRange(progress, 0.6f, 1f, 255, 0);
circlePaints[0].setAlpha(alpha);
circlePaints[1].setAlpha(alpha);
circlePaints[2].setAlpha(alpha);
circlePaints[3].setAlpha(alpha);
}
public static final Property<DotsView, Float> DOTS_PROGRESS = new Property<DotsView, Float>(Float.class, "dotsProgress") {
@Override
public Float get(DotsView object) {
return object.getCurrentProgress();
}
@Override
public void set(DotsView object, Float value) {
object.setCurrentProgress(value);
}
};
}
四:LikeButtonView
最終的ViewGroup是由CircleView, ImageView 以及DotsView組成的。
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<frogermcs.io.likeanimation.DotsView
android:id="@+id/vDotsView"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"/>
<frogermcs.io.likeanimation.CircleView
android:id="@+id/vCircle"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"/>
<ImageView
android:id="@+id/ivStar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_star_rate_off"/>
</merge>
我們使用 Merge 標籤幫助消除多餘的ViewGroup。LikeButtonView本身就是一個FrameLayout,因此沒有必要出現兩次。
我們最終的動畫是由更小的動畫組成的,通過AnimatorSet一起播放:
LikeButtonView完整代碼
package com.loveta.umengexample;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import butterknife.Bind;
import butterknife.ButterKnife;
/**
* Created by Miroslaw Stanek on 20.12.2015.
*/
public class LikeButtonView extends FrameLayout implements View.OnClickListener {
private static final DecelerateInterpolator DECCELERATE_INTERPOLATOR = new DecelerateInterpolator();
private static final AccelerateDecelerateInterpolator ACCELERATE_DECELERATE_INTERPOLATOR = new AccelerateDecelerateInterpolator();
private static final OvershootInterpolator OVERSHOOT_INTERPOLATOR = new OvershootInterpolator(4);
@Bind(R.id.ivStar)
ImageView ivStar;
@Bind(R.id.vDotsView)
DotsView vDotsView;
@Bind(R.id.vCircle)
CircleView vCircle;
private boolean isChecked;
private AnimatorSet animatorSet;
public LikeButtonView(Context context) {
super(context);
init();
}
public LikeButtonView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LikeButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public LikeButtonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
LayoutInflater.from(getContext()).inflate(R.layout.view_like_button, this, true);
ButterKnife.bind(this);
setOnClickListener(this);
}
@Override
public void onClick(View v) {
// Log.e("==tjj======",v.getId()+"");
isChecked = !isChecked;
ivStar.setImageResource(isChecked ? R.drawable.smart11 : R.drawable.smart1);
if (animatorSet != null) {
animatorSet.cancel();
}
if (isChecked) {
ivStar.animate().cancel();
ivStar.setScaleX(0);
ivStar.setScaleY(0);
Log.e("====1111=======", "setCurrentProgress");
vCircle.setInnerCircleRadiusProgress(0);
vCircle.setOuterCircleRadiusProgress(0);
vDotsView.setCurrentProgress(0);
animatorSet = new AnimatorSet();
ObjectAnimator outerCircleAnimator = ObjectAnimator.ofFloat(vCircle, CircleView.OUTER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f);
outerCircleAnimator.setDuration(250);
outerCircleAnimator.setInterpolator(DECCELERATE_INTERPOLATOR);
ObjectAnimator innerCircleAnimator = ObjectAnimator.ofFloat(vCircle, CircleView.INNER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f);
innerCircleAnimator.setDuration(200);
innerCircleAnimator.setStartDelay(200);
innerCircleAnimator.setInterpolator(DECCELERATE_INTERPOLATOR);
ObjectAnimator starScaleYAnimator = ObjectAnimator.ofFloat(ivStar, ImageView.SCALE_Y, 0.2f, 1f);
starScaleYAnimator.setDuration(350);
starScaleYAnimator.setStartDelay(250);
starScaleYAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR);
ObjectAnimator starScaleXAnimator = ObjectAnimator.ofFloat(ivStar, ImageView.SCALE_X, 0.2f, 1f);
starScaleXAnimator.setDuration(350);
starScaleXAnimator.setStartDelay(250);
starScaleXAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR);
ObjectAnimator dotsAnimator = ObjectAnimator.ofFloat(vDotsView, DotsView.DOTS_PROGRESS, 0, 1f);
dotsAnimator.setDuration(900);
dotsAnimator.setStartDelay(50);
dotsAnimator.setInterpolator(ACCELERATE_DECELERATE_INTERPOLATOR);
animatorSet.playTogether(
outerCircleAnimator,
innerCircleAnimator,
starScaleYAnimator,
starScaleXAnimator,
dotsAnimator
);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
vCircle.setInnerCircleRadiusProgress(0);
vCircle.setOuterCircleRadiusProgress(0);
// Log.e("====2222=======", "setCurrentProgress");
vDotsView.setCurrentProgress(0);
ivStar.setScaleX(1);
ivStar.setScaleY(1);
}
});
animatorSet.start();
}
}
//LikeButtonView還會響應觸摸事件(縮放動畫):
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
ivStar.animate().scaleX(0.7f).scaleY(0.7f).setDuration(150).setInterpolator(DECCELERATE_INTERPOLATOR);
setPressed(true);
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
boolean isInside = (x > 0 && x < getWidth() && y > 0 && y < getHeight());
if (isPressed() != isInside) {
setPressed(isInside);
}
break;
case MotionEvent.ACTION_UP:
ivStar.animate().scaleX(1).scaleY(1).setInterpolator(DECCELERATE_INTERPOLATOR);
if (isPressed()) {
performClick();
setPressed(false);
}
break;
}
return true;
}
}
源代碼可以在github上面得到:https://github.com/frogermcs/LikeAnimation/