做一個商品加入購物車的效果,之前一直想嘗試去實作,無奈啊,沒機會。緻謝 nianxin 徐宜生
001.gif
怎麼用?
<pre>
public void addAction(View view) {
new DriftingTextView(this)
.startView(view)
.rootView(getWindow().getDecorView())
.endView(btCart)
.startBesselAnim();
}
</pre>
代碼很少
package github.alex.jumpview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.TextView;
/**
* 漂移的文本控件
* 作者:alex
* 時間:2016/7/28 10:54
* 部落格位址:
http://www.jianshu.com/users/c3c4ea133871/subscriptions*/
public class DriftingTextView extends TextView {
private GradientDrawable gradientDrawable;
private static final int VIEW_SIZE = 20;
/\*\*
\* 控件的半徑
\*/
protected int radius;
/\*\*
\* 起點
\*/
protected Point startPoint;
/\*\*
\* 終點
\*/
protected Point endPoint;
/\*\*
\* 漂移的時間
\*/
private long driftingDuration;
public DriftingTextView(Context context) {
super(context);
initView();
}
public DriftingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
driftingDuration = 500;
gradientDrawable = new GradientDrawable();
gradientDrawable.setShape(GradientDrawable.OVAL);
gradientDrawable.setColor(Color.parseColor("#FF0000"));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
setBackground(gradientDrawable);
} else {
setBackgroundDrawable(gradientDrawable);
}
setGravity(Gravity.CENTER);
setText("1");
setTextColor(Color.WHITE);
setTextSize(10);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = (int) dp2Px(VIEW_SIZE);
setMeasuredDimension(size, size);
radius = size / 2;
}
/\*\*
\* 設定 起始點
\*/
public DriftingTextView startPoint(Point startPoint) {
startPoint.y -= 10;
this.startPoint = startPoint;
return this;
}
/\*\*
\* 設定 起始點的 控件
\*/
public DriftingTextView startView(View view) {
int position[] = new int[2];
view.getLocationInWindow(position);
startPoint(new Point(position[0], position[1]));
return this;
}
/\*\*
\* 設定 結束點
\*/
public DriftingTextView endPoint(Point endPoint) {
this.endPoint = endPoint;
return this;
}
/\*\*
\* 設定 結束點的 控件
\*/
public DriftingTextView endView(View view) {
int position[] = new int[2];
view.getLocationInWindow(position);
endPoint(new Point(position[0], position[1]));
return this;
}
/\*\*
\* 設定漂移文本控件的 父控件
\*/
public DriftingTextView rootView(ViewGroup viewGroup) {
viewGroup.addView(this);
return this;
}
/\*\*
\* 設定漂移文本控件的 父控件
\*/
public DriftingTextView rootView(View view) {
if(view instanceof ViewGroup){
ViewGroup viewGroup = (ViewGroup) view;
viewGroup.addView(this);
}
return this;
}
/\*\*
\* 設定 漂移時間
\*
\* @param driftingDuration 漂移時間,機關 ms
\* 如果小于 20ms,或者大于 5000ms,使用預設時間500ms
\*/
public DriftingTextView driftingDuration(long driftingDuration) {
if ((driftingDuration < 20) || (driftingDuration > 5000)) {
driftingDuration = 500;
}
this.driftingDuration = driftingDuration;
return this;
}
public void startBesselAnim() {
if (startPoint == null || endPoint == null) return;
int pointX = (startPoint.x + endPoint.x) / 2;
int pointY = (int) (startPoint.y - dp2Px(100));
Point driftingPoint = new Point(pointX, pointY);
BesselEvaluator bezierEvaluator = new BesselEvaluator(driftingPoint);
ValueAnimator anim = ValueAnimator.ofObject(bezierEvaluator, startPoint, endPoint);
anim.addUpdateListener(new MyAnimatorUpdateListener());
anim.setDuration(driftingDuration);
anim.addListener(new MyAnimatorListenerAdapter());
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.start();
}
private final class MyAnimatorListenerAdapter extends AnimatorListenerAdapter {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
ViewGroup viewGroup = (ViewGroup) getParent();
viewGroup.removeView(DriftingTextView.this);
}
}
private final class MyAnimatorUpdateListener implements ValueAnimator.AnimatorUpdateListener {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Point point = (Point) valueAnimator.getAnimatedValue();
setX(point.x);
setY(point.y);
invalidate();
}
}
public class BesselEvaluator implements TypeEvaluator<Point> {
private Point driftingPoint;
public BesselEvaluator(Point driftingPoint) {
this.driftingPoint = driftingPoint;
}
@Override
public Point evaluate(float t, Point startValue, Point endValue) {
int x = (int) ((1 - t) \* (1 - t) \* startValue.x + 2 \* t \* (1 - t) \* driftingPoint.x + t \* t \* endValue.x);
int y = (int) ((1 - t) \* (1 - t) \* startValue.y + 2 \* t \* (1 - t) \* driftingPoint.y + t \* t \* endValue.y);
return new Point(x, y);
}
}
/\*\*
\* 資料轉換: dp---->px
\*/
private float dp2Px(float dp) {
return dp \* getContext().getResources().getDisplayMetrics().density;
}
/\*\*
\* sp轉px
\*/
private float sp2px(float sp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getContext().getResources().getDisplayMetrics());
}
public class BezierUtil {
/\*\*
\* B(t) = (1 - t)^2 \* P0 + 2t \* (1 - t) \* P1 + t^2 \* P2, t ∈ [0,1]
\*
\* @param t 曲線長度比例
\* @param p0 起始點
\* @param p1 控制點
\* @param p2 終止點
\* @return t對應的點
\*/
public static PointF CalculateBezierPointForQuadratic(float t, PointF p0, PointF p1, PointF p2) {
PointF point = new PointF();
float temp = 1 - t;
point.x = temp \* temp \* p0.x + 2 \* t \* temp \* p1.x + t \* t \* p2.x;
point.y = temp \* temp \* p0.y + 2 \* t \* temp \* p1.y + t \* t \* p2.y;
return point;
}
/\*\*
\* B(t) = P0 \* (1-t)^3 + 3 \* P1 \* t \* (1-t)^2 + 3 \* P2 \* t^2 \* (1-t) + P3 \* t^3, t ∈ [0,1]
\*
\* @param t 曲線長度比例
\* @param p0 起始點
\* @param p1 控制點1
\* @param p2 控制點2
\* @param p3 終止點
\* @return t對應的點
\*/
public static PointF CalculateBezierPointForCubic(float t, PointF p0, PointF p1, PointF p2, PointF p3) {
PointF point = new PointF();
float temp = 1 - t;
point.x = p0.x \* temp \* temp \* temp + 3 \* p1.x \* t \* temp \* temp + 3 \* p2.x \* t \* t \* temp + p3.x \* t \* t \* t;
point.y = p0.y \* temp \* temp \* temp + 3 \* p1.y \* t \* temp \* temp + 3 \* p2.y \* t \* t \* temp + p3.y \* t \* t \* t;
return point;
}