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

一、引入

其实之前一直以为像饿了么或者是美团外卖那种把商品添加到购物车的动画会很难做,但是实际做起来好像并没有想象中的那么难哈哈。

布局主要使用CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+TabLayout+ViewPager

动画主要使用二阶贝塞尔曲线与属性动画

消息传递使用EventBus普通事件

42ffcff908f89e549d73199a11d4ecc6.gif

二、大致思路

789feb424597a2b87bb83dd2f48bc789.png

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) {

}

});

}

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

8078b7683621f55014f097c3788567c7.png

xmlns:app="http://schemas.android.com/apk/res-auto"

... ...>

... ...>

顶部常驻的toolbar

android:layout_width="match_parent"

android:layout_height="0dp"

android:layout_weight="1">

... ...>

... ...

app:layout_scrollFlags="scroll|exitUntilCollapsed">

... ...>

TabLayout上面的View

... ... />

... ...

android:fillViewport="true"

app:layout_behavior="@string/appbar_scrolling_view_behavior">

android:id="@+id/view_pager"

android:layout_width="match_parent"

android:layout_height="match_parent" />

... ...>

最下面的购物车一栏

五、推荐资源

总结

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值