温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android利用二阶贝塞尔曲线实现添加购物车动画详解

发布时间:2020-08-30 11:58:16 来源:脚本之家 阅读:157 作者:张钦 栏目:移动开发

一、引入

  1. 其实之前一直以为像饿了么或者是美团外卖那种把商品添加到购物车的动画会很难做,但是实际做起来好像并没有想象中的那么难哈哈。
  2. 布局主要使用CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+TabLayout+ViewPager
  3. 动画主要使用二阶贝塞尔曲线与属性动画
  4. 消息传递使用EventBus普通事件

Android利用二阶贝塞尔曲线实现添加购物车动画详解

二、大致思路

Android利用二阶贝塞尔曲线实现添加购物车动画详解

1、如图所示主要有三个点,起点、终点、以及贝塞尔曲线的控制点

2、起点即点击的View的位置,一般来说用如下方式即可取得。startPosition[0]为x轴开始坐标,startPosition[1]为Y轴终点坐标,两点可以看作对角线上面的两个端点(左上角x坐标,右下角y坐标)

//贝塞尔起始数据点
int[] startPosition = new int[2];
view.getLocationOnScreen(startPosition);

3、终点即购物车篮子的位置,与起点类似

mShoppingCart.getLocationInWindow(endPosition);

4、控制点,我选的控制点为上图的C点,即A点的y坐标,B点的X坐标

controlPosition[0] = endPosition[0];
controlPosition[1] = startPosition[1];

5、需要注意的地方,我不清楚是不是因为我的布局的问题,获取到的点击的A点总是会有一个偏移,后来经同事提醒,减去了TabLayout的坐标的y轴坐标即位置才可以。

// 起点
int[] startPosition;
// 终点
int[] endPosition = new int[2];
// 贝塞尔控制点
int[] controlPosition = new int[2];
// tablayout位置
int[] tablayoutPosition = new int[2];

startPosition = data.getStartPosition();
mShoppingCart.getLocationInWindow(endPosition);
mTabLayout.getLocationInWindow(tablayoutPosition);
// 处理起点y坐标偏移的问题
startPosition[1] = startPosition[1] - tablayoutPosition[1] - mTabLayout.getHeight();
// 终点进行一下居中处理
endPosition[0] = endPosition[0] + (mShoppingCart.getWidth() / 2);
controlPosition[0] = endPosition[0];
controlPosition[1] = startPosition[1];

6、通过Path的quadTo方法绘制贝塞尔曲线,使用PathMeasure获取点的坐标(借助ValueAnimator.ofFloat()配合getPosTan()来获取坐标)

Path path = new Path();
path.moveTo(startPosition[0], startPosition[1]);
path.quadTo(controlPosition[0], controlPosition[1], endPosition[0], endPosition[1]);
PathMeasure pathMeasure = new PathMeasure();
// false表示path路径不闭合
pathMeasure.setPath(path, false);

// ofFloat是一个生成器
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, pathMeasure.getLength());
// 匀速线性插值器
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setDuration(800);
valueAnimator.addUpdateListener(animation -> {
 float value = (Float) animation.getAnimatedValue();
 pathMeasure.getPosTan(value, currentPosition, null);
 imageView.setX(currentPosition[0]);
 imageView.setY(currentPosition[1]);
});
valueAnimator.start();

7、下面是用属性动画给购物车篮子做了一个放大缩小的动画效果

// mShoppingCart是View
ObjectAnimator shoppingCartX = ObjectAnimator.ofFloat(mShoppingCart, "scaleX", 1.0f, 1.3f, 1.0f);
ObjectAnimator shoppingCartY = ObjectAnimator.ofFloat(mShoppingCart, "scaleY", 1.0f, 1.3f, 1.0f);
shoppingCartX.setInterpolator(new AccelerateInterpolator());
shoppingCartY.setInterpolator(new AccelerateInterpolator());
AnimatorSet shoppingCart = new AnimatorSet();
shoppingCart
 .play(shoppingCartX)
 .with(shoppingCartY);
shoppingCart.setDuration(800);
shoppingCart.start();

三、稍完整的大部分代码

private void AddAnimation(AddEventBean data) {
 // 起点
 int[] startPosition;
 // 终点
 int[] endPosition = new int[2];
 // 贝塞尔控制点
 int[] controlPosition = new int[2];
 // 当前位置
 float[] currentPosition = new float[2];
 // tablayout位置
 int[] tablayoutPosition = new int[2];

 startPosition = data.getStartPosition();
 mShoppingCart.getLocationInWindow(endPosition);
 mTabLayout.getLocationInWindow(tablayoutPosition);
 // 处理起点y坐标偏移的问题
 startPosition[1] = startPosition[1] - tablayoutPosition[1] - mTabLayout.getHeight();
 // 终点进行一下居中处理
 endPosition[0] = endPosition[0] + (mShoppingCart.getWidth() / 2);
 controlPosition[0] = endPosition[0];
 controlPosition[1] = startPosition[1];


 final ImageView imageView = new ImageView(this);
 mConView.addView(imageView);
 imageView.setImageResource(R.drawable.specialadd);
 imageView.getLayoutParams().width = getResources().getDimensionPixelSize(R.dimen.dp_px_30);
 imageView.getLayoutParams().height = getResources().getDimensionPixelSize(R.dimen.dp_px_30);
 imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
 imageView.setVisibility(View.VISIBLE);
 imageView.setX(startPosition[0]);
 imageView.setY(startPosition[1]);

 Path path = new Path();
 path.moveTo(startPosition[0], startPosition[1]);
 path.quadTo(controlPosition[0], controlPosition[1], endPosition[0], endPosition[1]);
 PathMeasure pathMeasure = new PathMeasure();
 // false表示path路径不闭合
 pathMeasure.setPath(path, false);

 // ofFloat是一个生成器
 ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, pathMeasure.getLength());
 // 匀速线性插值器
 valueAnimator.setInterpolator(new LinearInterpolator());
 valueAnimator.setDuration(800);
 valueAnimator.addUpdateListener(animation -> {
 float value = (Float) animation.getAnimatedValue();
 pathMeasure.getPosTan(value, currentPosition, null);
 imageView.setX(currentPosition[0]);
 imageView.setY(currentPosition[1]);
 });
 valueAnimator.start();

 ObjectAnimator shoppingCartX = ObjectAnimator.ofFloat(mShoppingCart, "scaleX", 1.0f, 1.3f, 1.0f);
 ObjectAnimator shoppingCartY = ObjectAnimator.ofFloat(mShoppingCart, "scaleY", 1.0f, 1.3f, 1.0f);
 shoppingCartX.setInterpolator(new AccelerateInterpolator());
 shoppingCartY.setInterpolator(new AccelerateInterpolator());
 AnimatorSet shoppingCart = new AnimatorSet();
 shoppingCart
 .play(shoppingCartX)
 .with(shoppingCartY);
 shoppingCart.setDuration(800);
 shoppingCart.start();

 valueAnimator.addListener(new Animator.AnimatorListener() {
 @Override
 public void onAnimationStart(Animator animation) {

 }

 //当动画结束后:
 @Override
 public void onAnimationEnd(Animator animation) {
 goodsChange(data);
 }

 @Override
 public void onAnimationCancel(Animator animation) {

 }

 @Override
 public void onAnimationRepeat(Animator animation) {

 }
 });
}

四、大致写下布局(同时也算留做备份)

Android利用二阶贝塞尔曲线实现添加购物车动画详解

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 ... ...>

 <RelativeLayout
 ... ...>

 顶部常驻的toolbar

 </RelativeLayout>

 <android.support.design.widget.CoordinatorLayout
 android:layout_width="match_parent"
 android:layout_height="0dp"
 android:layout_weight="1">

 <android.support.design.widget.AppBarLayout
 ... ...>

 <android.support.design.widget.CollapsingToolbarLayout
 ... ...
 app:layout_scrollFlags="scroll|exitUntilCollapsed">

 <LinearLayout
  ... ...>

  TabLayout上面的View
  
 </LinearLayout>

 </android.support.design.widget.CollapsingToolbarLayout>

 <android.support.design.widget.TabLayout
 ... ... />

 </android.support.design.widget.AppBarLayout>

 <RelativeLayout
 ... ...
 android:fillViewport="true"
 app:layout_behavior="@string/appbar_scrolling_view_behavior">

 <android.support.v4.view.ViewPager
 android:id="@+id/view_pager"
 android:layout_width="match_parent"
 android:layout_height="match_parent" />
 </RelativeLayout>

 </android.support.design.widget.CoordinatorLayout>

 <LinearLayout
 ... ...>

 最下面的购物车一栏
 
 </LinearLayout>
</LinearLayout>

五、推荐资源

View的位置参数

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对亿速云的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI