版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_37717853/article/details/87879695
上一篇: Android贝塞尔曲线的简单应用之——实现自定义圆形控件内水波纹自动上升效果Demo
效果:
布局这里很简单,一个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;//结束点控件
/**
* 构造方法
* @param layout 布局文件,即xml文件的根布局layout,用于确定子view的相对位置
* @param startView 曲线开始的控件
* @param endView 曲线结束的控件(一般是”购物车“)
*/
public BezierShopCarModule (ViewGroup layout, View startView, View endView){
this.layout = layout;
this.startView = startView;
this.endView = endView;
}
然后是实现动画效果的方法,下面有注释:
/**
* 开启贝塞尔曲线动画效果
* @param context 传入的view所在的activity的上下文变量
* @param animationTime 动画执行时间
* @param imageViewResource 图片资源
* @param imageWidth 图片控件宽度
* @param imageHeight 图片控件高度
* @return 执行结束,返回true
*/
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];//确定起始点Y坐标
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;
}
最后还有一个自定义的插值器,这是实现贝塞尔曲线的关键:
/**
* Created by Given on 2019/2/22 0022.
* 自定义插值器,用于实现贝塞尔曲线效果
*/
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;
}
}