购物车添加商品实现轨迹动画
先看下实现效果
分析下实现原理,起始点是添加按钮,购物车是结束点,
我们把控制点的x坐标设定为结束点的x左边,y左边设定为添加按钮的y坐标,用贝塞尔的二阶曲线即可实现该效果。
1.确定view的位置坐标
getLocationInWindow是以B为原点的C的坐标
getLocationOnScreen是以A为原点的C的坐标
2.拿到关键点的坐标后我们需要提供关于坐标的估值器
实现TypeEvaluator的evaluate方法
这里提供了3个回调参数,它们分别代表:
float fraction:动画的完成程度,0~1
T startValue:动画开始值
T endValue: 动画结束值(这里而外补充一点,要想得到当前的动画值其实也很简单,只需要用(动画开始值+动画完成程度*动画结束值))
在自己的估值器中用二阶贝塞尔函数实现相应的坐标转换
public class PointEvaluate implements TypeEvaluator<PointF> {
private PointF controllerValue;
public PointEvaluate(PointF controllerValue) {
this.controllerValue = controllerValue;
}
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
float x = (1 - fraction) * (1 - fraction) * startValue.x + 2 * (1 - fraction) * fraction * controllerValue.x + fraction * fraction * endValue.x;
float y = (1 - fraction) * (1 - fraction) * startValue.y + 2 * (1 - fraction) * fraction * controllerValue.y + fraction * fraction * endValue.y;
return new PointF(x, y);
}
}
3.我们可以在点击添加按钮的时候new一个imageView,让他的动画是从无到有(sacle,alpha动画),最后在运动轨迹变化的回调时不断变化imagview的位置.
public class ShopActivity extends AppCompatActivity {
private ImageView ivCar, ivRemove, ivAdd;
private int[] addView = new int[2];
private int[] shopView = new int[2];
private int[] parentView = new int[2];
private RelativeLayout rlMain;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shop);
ivCar = findViewById(R.id.ivCar);
rlMain = findViewById(R.id.rlMain);
ivRemove = findViewById(R.id.ivRemove);
ivAdd = findViewById(R.id.ivAdd);
ivAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ivAdd.getLocationInWindow(addView);
rlMain.getLocationInWindow(parentView);
ivCar.getLocationInWindow(shopView);
final PointF startF = new PointF(addView[0] - parentView[0], addView[1] - parentView[1]);
final PointF endF = new PointF(shopView[0] - parentView[0], shopView[1] - parentView[1]);
final PointF controllerF = new PointF(endF.x, startF.y);
final ImageView imageView = new ImageView(ShopActivity.this);
imageView.setImageResource(R.mipmap.ic_car);
imageView.setScaleX(0);
imageView.setScaleY(0);
rlMain.addView(imageView);
imageView.setX(startF.x);
imageView.setY(startF.y);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluate(controllerF), startF, endF);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
imageView.setX(pointF.x);
imageView.setY(pointF.y);
imageView.setScaleY(animation.getAnimatedFraction());
imageView.setScaleX(animation.getAnimatedFraction());
}
});
valueAnimator.setDuration(1000);
valueAnimator.setTarget(imageView);
valueAnimator.start();
}
});
}
}
这样就可以实现贝塞尔的二阶运动轨迹了。