Question

  • 贝塞尔曲线是什么?
  • 贝塞尔曲线可以做什么?
  • 怎么做?

What is it ?

贝塞尔曲线在百度定义是贝塞尔曲线(Bézier curve),又称 贝兹 曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。

Usage

贝塞尔曲线根据不同点实现不同动态效果:

  • 一阶贝塞尔曲线(两点),绘制成一条直线

  • 二阶贝塞尔曲线(三点)

  • 三阶贝塞尔曲线(四点)

  • 四阶贝塞尔曲线(五点)

  • 五阶贝塞尔曲线(六点)

看了上面贝塞尔曲线不同点不同效果后,相信大家都清楚贝塞尔曲线能干什么?没错,贝塞尔曲线能造高逼格动画

就笔者目前了解的采用贝塞尔曲线实现的知名开源项目有:

  • QQ拖拽清除效果

  • 纸飞机刷新动画

  • 滴油刷新动画

  • 波浪动画

到此大家是不是很兴奋,想更多了解如何造一个高逼格贝塞尔曲线动画。接下来我就给大家讲述如何造一个基于贝塞尔曲线实现的购物车动画,大家擦亮眼睛啦~~

How to do it ?

思路

  • 确定动画起终点

  • 在起终点之间使用二次贝塞尔曲线填充起终点之间点的轨迹

  • 设置属性动画,ValueAnimator插值器,获取中间点的坐标

  • 将执行动画控件的x、y坐标设为上面得到的中间点坐标

  • 开启属性动画

  • 当动画结束时的操作

知识点

  • Android中提供了绘制一阶、二阶、三阶的接口:

    • 一阶接口:

      public void lineTo(float x,float y)
    • 二阶接口:
      public void quadTo(float x1, float y1, float x2, float y2)
    • 三阶接口:
      public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
  • PathMeasure使用

    • getLength()

    • 理解 boolean getPosTan(float distance, float[] pos, float[] tan)

  • 如何获取控件在屏幕中的绝对坐标

    • int[] location = new int[2]; view.getLocationInWindow(location); 得到view在屏幕中的绝对坐标。

  • 理解属性动画插值器ValueAnimator

Code

首先写购物车布局xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/rly_bezier_curve_shopping_cart"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"><FrameLayoutandroid:id="@+id/fly_bezier_curve_shopping_cart"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:paddingRight="30dp"android:layout_alignParentStart="true"><ImageViewandroid:id="@+id/iv_bezier_curve_shopping_cart"android:layout_width="40dp"android:layout_height="40dp"android:layout_gravity="right"android:src="@drawable/menu_shop_car_selected" /><TextViewandroid:id="@+id/tv_bezier_curve_shopping_cart_count"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="@color/white"android:background="@drawable/corner_view"android:text="0"android:layout_gravity="right"/></FrameLayout><ListViewandroid:id="@+id/lv_bezier_curve_shopping_cart"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@+id/fly_bezier_curve_shopping_cart"/>
</RelativeLayout>

然后写购物车适配器、实体类,代码如下:

/*** @className: GoodsAdapter* @classDescription: 购物车商品适配器* @author: leibing* @createTime: 2016/09/28*/
public class GoodsAdapter extends BaseAdapter {// 数据源(购物车商品图片)private ArrayList<GoodsModel> mData;// 布局private LayoutInflater mLayoutInflater;// 回调监听private CallBackListener mCallBackListener;/*** 构造函数* @author leibing* @createTime 2016/09/28* @lastModify 2016/09/28* @param context 上下文* @param mData 数据源(购物车商品图片)* @return*/public GoodsAdapter(Context context, ArrayList<GoodsModel> mData){mLayoutInflater = LayoutInflater.from(context);this.mData = mData;}@Overridepublic int getCount() {return mData != null ? mData.size(): 0;}@Overridepublic Object getItem(int i) {return mData != null ? mData.get(i): null;}@Overridepublic long getItemId(int i) {return i;}@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {ViewHolder viewHolder;if (view == null){view = mLayoutInflater.inflate(R.layout.adapter_shopping_cart_item, null);viewHolder = new ViewHolder(view);view.setTag(viewHolder);}else {// 复用ViewHolderviewHolder = (ViewHolder) view.getTag();}// 更新UIif (i < mData.size())viewHolder.updateUI(mData.get(i));return view;}/*** @className: ViewHolder* @classDescription: 商品ViewHolder* @author: leibing* @createTime: 2016/09/28*/class  ViewHolder {// 显示商品图片private ImageView mShoppingCartItemIv;/*** 构造函数* @author leibing* @createTime 2016/09/28* @lastModify 2016/09/28* @param view 视图* @return*/public ViewHolder(View view){// findViewmShoppingCartItemIv = (ImageView) view.findViewById(R.id.iv_shopping_cart_item);// onClickview.findViewById(R.id.tv_shopping_cart_item).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {if (mShoppingCartItemIv != null && mCallBackListener != null)mCallBackListener.callBackImg(mShoppingCartItemIv);}});}/*** 更新UI* @author leibing* @createTime 2016/09/28* @lastModify 2016/09/28* @param goods 商品实体对象* @return*/public void updateUI(GoodsModel goods){if (goods != null&& goods.getmGoodsBitmap() != null&& mShoppingCartItemIv != null)mShoppingCartItemIv.setImageBitmap(goods.getmGoodsBitmap());}}/*** 设置回调监听* @author leibing* @createTime 2016/09/28* @lastModify 2016/09/28* @param mCallBackListener 回调监听* @return*/public void setCallBackListener(CallBackListener mCallBackListener){this.mCallBackListener = mCallBackListener;}/*** @interfaceName: CallBackListener* @interfaceDescription: 回调监听* @author: leibing* @createTime: 2016/09/28*/public interface CallBackListener{void callBackImg(ImageView goodsImg);}
}
然后写添加数据源以及设置适配器,代码如下:
    // 购物车父布局private RelativeLayout mShoppingCartRly;// 购物车列表显示private ListView mShoppingCartLv;// 购物数目显示private TextView mShoppingCartCountTv;// 购物车图片显示private ImageView mShoppingCartIv;// 购物车适配器private GoodsAdapter mGoodsAdapter;// 数据源(购物车商品图片)private ArrayList<GoodsModel> mData;// 贝塞尔曲线中间过程点坐标private float[] mCurrentPosition = new float[2];// 路径测量private PathMeasure mPathMeasure;// 购物车商品数目private int goodsCount = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// findViewmShoppingCartLv = (ListView) findViewById(R.id.lv_bezier_curve_shopping_cart);mShoppingCartCountTv = (TextView) findViewById(R.id.tv_bezier_curve_shopping_cart_count);mShoppingCartRly = (RelativeLayout) findViewById(R.id.rly_bezier_curve_shopping_cart);mShoppingCartIv = (ImageView) findViewById(R.id.iv_bezier_curve_shopping_cart);// 是否显示购物车商品数目isShowCartGoodsCount();// 添加数据源addData();// 设置适配器setAdapter();}/*** 设置适配器* @author leibing* @createTime 2016/09/28* @lastModify 2016/09/28* @param* @return*/private void setAdapter() {// 初始化适配器mGoodsAdapter = new GoodsAdapter(this, mData);// 设置适配器监听mGoodsAdapter.setCallBackListener(new GoodsAdapter.CallBackListener() {@Overridepublic void callBackImg(ImageView goodsImg) {// 添加商品到购物车addGoodsToCart(goodsImg);}});// 设置适配器mShoppingCartLv.setAdapter(mGoodsAdapter);}
接下来写最重要的一块,添加商品到购物车,代码如下:

/*** 添加商品到购物车* @author leibing* @createTime 2016/09/28* @lastModify 2016/09/28* @param goodsImg 商品图标* @return*/private void addGoodsToCart(ImageView goodsImg) {// 创造出执行动画的主题goodsImg(这个图片就是执行动画的图片,从开始位置出发,经过一个抛物线(贝塞尔曲线),移动到购物车里)final ImageView goods = new ImageView(this);goods.setImageDrawable(goodsImg.getDrawable());RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);mShoppingCartRly.addView(goods, params);// 得到父布局的起始点坐标(用于辅助计算动画开始/结束时的点的坐标)int[] parentLocation = new int[2];mShoppingCartRly.getLocationInWindow(parentLocation);// 得到商品图片的坐标(用于计算动画开始的坐标)int startLoc[] = new int[2];goodsImg.getLocationInWindow(startLoc);// 得到购物车图片的坐标(用于计算动画结束后的坐标)int endLoc[] = new int[2];mShoppingCartIv.getLocationInWindow(endLoc);// 开始掉落的商品的起始点:商品起始点-父布局起始点+该商品图片的一半float startX = startLoc[0] - parentLocation[0] + goodsImg.getWidth() / 2;float startY = startLoc[1] - parentLocation[1] + goodsImg.getHeight() / 2;// 商品掉落后的终点坐标:购物车起始点-父布局起始点+购物车图片的1/5float toX = endLoc[0] - parentLocation[0] + mShoppingCartIv.getWidth() / 5;float toY = endLoc[1] - parentLocation[1];// 开始绘制贝塞尔曲线Path path = new Path();// 移动到起始点(贝塞尔曲线的起点)path.moveTo(startX, startY);// 使用二阶贝塞尔曲线:注意第一个起始坐标越大,贝塞尔曲线的横向距离就会越大,一般按照下面的式子取即可path.quadTo((startX + toX) / 2, startY, toX, toY);// mPathMeasure用来计算贝塞尔曲线的曲线长度和贝塞尔曲线中间插值的坐标,如果是true,path会形成一个闭环mPathMeasure = new PathMeasure(path, false);// 属性动画实现(从0到贝塞尔曲线的长度之间进行插值计算,获取中间过程的距离值)ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());valueAnimator.setDuration(500);// 匀速线性插值器valueAnimator.setInterpolator(new LinearInterpolator());valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {// 当插值计算进行时,获取中间的每个值,// 这里这个值是中间过程中的曲线长度(下面根据这个值来得出中间点的坐标值)float value = (Float) animation.getAnimatedValue();// 获取当前点坐标封装到mCurrentPosition// boolean getPosTan(float distance, float[] pos, float[] tan) :// 传入一个距离distance(0<=distance<=getLength()),然后会计算当前距离的坐标点和切线,pos会自动填充上坐标,这个方法很重要。// mCurrentPosition此时就是中间距离点的坐标值mPathMeasure.getPosTan(value, mCurrentPosition, null);// 移动的商品图片(动画图片)的坐标设置为该中间点的坐标goods.setTranslationX(mCurrentPosition[0]);goods.setTranslationY(mCurrentPosition[1]);}});// 开始执行动画valueAnimator.start();// 动画结束后的处理valueAnimator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {// 购物车商品数量加1goodsCount ++;isShowCartGoodsCount();mShoppingCartCountTv.setText(String.valueOf(goodsCount));// 把执行动画的商品图片从父布局中移除mShoppingCartRly.removeView(goods);}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});}

代码分析完毕,一个高逼格贝塞尔曲线实现的购物车添加商品动画效果实现分析完毕~~

效果图如下:

贝塞尔曲线之购物车动画效果相关推荐

  1. 贝塞尔曲线下的动画效果

    最近有一个需求是这样的:点赞后变化的数字从VIew的底部上浮到label的text的对应的需要改变的数字位置,替换该数字.(也就是说,如果点赞前该数字是158,点赞后变成159,那么从View底部飘上 ...

  2. 小程序二次贝塞尔曲线,购物车商品曲线飞入效果

    前段时间闲暇的时候看到一个贝塞尔曲线算法的文章,试着在小程序里去实现小程序的贝塞尔曲线算法,及其效果. 主要应用到的技术点: 1.小程序wxss布局,以及数据绑定 2.js二次bezier曲线算法 核 ...

  3. 贝塞尔曲线与CSS3动画、SVG和canvas的应用

    简介 贝塞尔曲线是可以做出很多复杂的效果来的,比如弹跳球的复杂动画效果,首先加速下降,停止,然后弹起时逐渐减速的效果. 使用贝塞尔曲线常用的两个网址如下: 缓动函数:http://www.xuanfe ...

  4. Android利用贝塞尔曲线实现翻书效果(适配AndroidX)

    实现背景 不知道你有没有遇到同样的问题,要实现翻书效果,如果你是使用github上的demo或者好多博客上写的方式,你会发现,当api从28开始,会抛出Invalid Region.Op.REPLAC ...

  5. android实现购物车效果,Android 实现蘑菇街购物车动画效果

    使用过蘑菇街的用户基本上都知道有一个加入购物车的动画效果,此处不具体描述想知道的可以去下载体验一下. 1.思路 目前想到两种方式实现这种效果,一是使用Tween动画,直截了当的进行一个移动,蘑菇街就是 ...

  6. css3贝塞尔曲线_CSS3动画–使用贝塞尔曲线创建具有弹跳效果的扇出

    您知道吗,可以使用transform CSS属性(例如缩放,倾斜和旋转)将动画转换添加到HTML元素中, ? 可以使用transition属性和@keyframes动画对它们进行动画@keyframe ...

  7. android京东加入购物车效果,京东360buy 手机项目的“加入购物车”动画效果研究...

    JingDong: When it render the "search result" page ,(every item has the picture) ,it will b ...

  8. 贝塞尔曲线 花束直播点赞效果

    1. 效果 先说一下这种效果都用到了哪些东西: 1.自定义View的一些基础: 2.随机数的使用: 3.插补器的使用: 4.属性动画的一些高级用法 5.贝塞尔曲线应用到属性动画 2.分析和实现 2.1 ...

  9. android 贝塞尔曲线 波浪线,Android 贝塞尔曲线实现水纹波动效果

    贝塞尔曲线简介 千篇一律,很多类似的文章都会介绍一下什么是贝塞尔曲线,但是这里就不做介绍了,我们在这里只需要知道在Android API为我们提供了绘制二阶贝塞尔曲线和三阶贝塞尔曲线的方法即可. 效果 ...

最新文章

  1. RecyclerView中adapter列表里有EditText输入框问题(使用不复用方法解决)
  2. Tomcat参数设置,解决内存溢出问题
  3. 如何高效地遍历 MongoDB 超大集合?
  4. mysql 备份 一张表_mysql 备份表的一个方法
  5. 诡异的编码和字节长度
  6. 数学之美:欣赏超越数e
  7. vue/iview使用moment.js
  8. List of Algorithms
  9. 程序员windows基础操作系列文章目录
  10. word 参考文献插入整理
  11. MATLAB:Your network connectionmay be down or your proxy settings improperly configured
  12. windows计算机锁屏的快捷键是什么,win7的锁屏快捷键是什么 win7锁屏快捷键介绍【图文】...
  13. 【docker】docker重新加载nginx配置
  14. Python 寻峰算法
  15. 集束搜索(Beam Search Algorithm )
  16. 基于STC15系列单片机课程中讲到的汇编指令(二)
  17. 高手教你ie主页被篡改怎么办|加个参数永远不怕IE主页被修改
  18. http请求HttpServletRequest详解
  19. 413:Calling Extraterrestrial Intelligence Again(翻译 )
  20. 气“疯”了!| 经济学人全球早读精选

热门文章

  1. 搜索引擎之ElasticSearch(es)入门学习、ELK 和 beats
  2. 二叉树的各种遍历方式,我都帮你总结了,附有队列堆栈图解
  3. python数据格式化之pprint
  4. SEO前线ZERO免费视频公开课
  5. CSS3 画点好玩的东西
  6. python:dlib在视频流中提取面部特征点
  7. pink老师课堂案例:简易的ATM机,学习前端开发一定要多动手实践
  8. CS224n-winter2019 exploring_word_vectors
  9. 【JAVAScript】【3】校验码实例(包含函数嵌套、闭包和window.onload)
  10. 小团队真的适合引入SpringCloud微服务吗?