效果:
佈局這裏很簡單,一個RecyclerView和一個ImageView,這裏稍微注意下,ConstraintLayout等下我們要用到,所以這裏加了id。
然後是在activity中設置recyclerview的adapter添加一些商品數據,在item的點擊監聽中調用封裝好的工具類:BezierShopCarModule,傳入指定參數,這樣就可以實現商品掉落到購物車的效果了,是不是很easy?哈哈,下面來介紹下封裝的類 BezierShopCarModule
private void setListener() {
callBack = new CallBack() {
@Override
public void itemOnClickListener(View view,int position) {
Log.i(TAG,"點擊了第"+position+"個item");
module = new BezierShopCarModule(clMain,view,ivShopCar);
module.bezierCurveAnimation(MainActivity.this,800,R.mipmap.commodity_phone,view.getWidth(),view.getHeight());
}
};
}
BezierShopCarModule 主要用到的方法就兩個而已,構造方法如下,這裏就要用到開頭說的constraintlayout,傳參的時候加上這個即可。
private ViewGroup layout;
private View startView;
private View endView;
public BezierShopCarModule (ViewGroup layout, View startView, View endView){
this.layout = layout;
this.startView = startView;
this.endView = endView;
}
然後是實現動畫效果的方法,下面有註釋:
public boolean bezierCurveAnimation(Context context,int animationTime,int imageViewResource,int imageWidth,int imageHeight){
int[] startPoint = new int[2];
int[] endPoint = new int[2];
int[] constraintLayoutPoint = new int[2];
layout.getLocationInWindow(constraintLayoutPoint);
startView.getLocationInWindow(startPoint);
endView.getLocationInWindow(endPoint);
PointF startF = new PointF();
PointF endF = new PointF();
PointF controllF = new PointF();
startF.x = startPoint[0];
startF.y = startPoint[1] - constraintLayoutPoint[1];
endF.x = endPoint[0]+(endView.getWidth()-imageWidth)/2;
endF.y = endPoint[1] - constraintLayoutPoint[1];
controllF.x = endF.x;
controllF.y = startF.y;
final ImageView imageView = new ImageView(context);
layout.addView(imageView);
imageView.setImageResource(imageViewResource);
imageView.getLayoutParams().width = imageWidth;
imageView.getLayoutParams().height = imageHeight;
imageView.setVisibility(View.VISIBLE);
imageView.setX(startF.x);
imageView.setY(startF.y);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new BezierTypeEvaluator(controllF),startF,endF);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
PointF pointF = (PointF) valueAnimator.getAnimatedValue();
imageView.setX(pointF.x);
imageView.setY(pointF.y);
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
layout.removeView(imageView);
}
});
ObjectAnimator objectAnimatorX = ObjectAnimator.ofFloat(endView,"scaleX",0.8f,1.0f);
ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(endView,"scaleY",0.8f,1.0f);
objectAnimatorX.setInterpolator(new AccelerateInterpolator());
objectAnimatorY.setInterpolator(new AccelerateInterpolator());
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(objectAnimatorX).with(objectAnimatorY).after(valueAnimator);
animatorSet.setDuration(animationTime);
animatorSet.start();
return true;
}
最後還有一個自定義的插值器,這是實現貝塞爾曲線的關鍵:
public class BezierTypeEvaluator implements TypeEvaluator<PointF> {
private PointF controllPoint;
public BezierTypeEvaluator(PointF controllPoint){
this.controllPoint = controllPoint;
}
@Override
public PointF evaluate(float v, PointF startValue, PointF endValue) {
PointF pointCur = new PointF();
pointCur.x = (1-v)*(1-v)*startValue.x + 2*v*(1-v)*controllPoint.x + v*v*endValue.x;
pointCur.y = (1-v)*(1-v)*startValue.y + 2*v*(1-v)*controllPoint.y + v*v*endValue.y;
return pointCur;
}
}