这里提供核心方法,流程便是:
listview列表监听事件,获取点击的图片控件,传入以下方法中。
方法流程:创建移动控件,获取传入控件坐标,获取目标控件位置,用path绘出贝塞尔曲线路径。用属性动画,移动控件改变位置。
方法如下:
private void addToCarAnimation(ImageView goodsImg) { //获取需要进行动画的ImageView final ImageView animImg = new ImageView(mContext); animImg.setImageDrawable(goodsImg.getDrawable()); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100); shellLayout.addView(animImg, params); // final int shellLocation[] = new int[2]; shellLayout.getLocationInWindow(shellLocation); int animImgLocation[] = new int[2]; goodsImg.getLocationInWindow(animImgLocation); int carLocation[] = new int[2]; carImage.getLocationInWindow(carLocation); // // 起始点:图片起始点-父布局起始点+该商品图片的一半-图片的marginTop || marginLeft 的值 float startX = animImgLocation[0] - shellLocation[0] + goodsImg.getWidth() / 2 - DpConvert.dip2px(mContext, 10.0f); float startY = animImgLocation[1] - shellLocation[1] + goodsImg.getHeight() / 2 - DpConvert.dip2px(mContext, 10.0f); // 商品掉落后的终点坐标:购物车起始点-父布局起始点+购物车图片的1/5 float endX = carLocation[0] - shellLocation[0] + carImage.getWidth() / 5; float endY = carLocation[1] - shellLocation[1]; //控制点,控制贝塞尔曲线 float ctrlX = (startX + endX) / 2; float ctrlY = startY - 100; Log.e("num", "-------->" + ctrlX + " " + startY + " " + ctrlY + " " + endY); Path path = new Path(); path.moveTo(startX, startY); // 使用二阶贝塞尔曲线 path.quadTo(ctrlX, ctrlY, endX, endY); mPathMeasure = new PathMeasure(path, false); ObjectAnimator scaleXanim = ObjectAnimator.ofFloat(animImg, "scaleX", 1, 0.5f, 0.2f); ObjectAnimator scaleYanim = ObjectAnimator.ofFloat(animImg, "scaleY", 1, 0.5f, 0.2f); ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // 这里这个值是中间过程中的曲线长度(下面根据这个值来得出中间点的坐标值) float value = (Float) animation.getAnimatedValue(); // 获取当前点坐标封装到mCurrentPosition // 传入一个距离distance(0<=distance<=getLength()),然后会计算当前距离的坐标点和切线, // pos会自动填充上坐标,这个方法很重要。 // mCurrentPosition此时就是中间距离点的坐标值 mPathMeasure.getPosTan(value, mCurrentPosition, null); // 移动的商品图片(动画图片)的坐标设置为该中间点的坐标 animImg.setTranslationX(mCurrentPosition[0]); animImg.setTranslationY(mCurrentPosition[1]); } }); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); goodsCount++; if (goodsCount < 100) { carCount.setText(String.valueOf(goodsCount)); } else { carCount.setText("99+"); } // 把执行动画的商品图片从父布局中移除 shellLayout.removeView(animImg); shopCarAnim(); } }); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(500); animatorSet.setInterpolator(new AccelerateInterpolator()); animatorSet.playTogether(scaleXanim, scaleYanim, valueAnimator); animatorSet.start(); }