仿饿了么加入购物车旋转控件

来源:互联网 发布:万能视频监控软件 编辑:程序博客网 时间:2024/04/29 00:00

今日科技快讯

近日,网易公布财报后,股价上涨至历史新高。主要受到游戏业务大获成功的推动,网易去年四季度收入猛增53%,达到17.4亿美元,业绩大幅超市场预期。业内人士表示,游戏行业整体依然维持较高景气度,游戏板块目前估值水平相对较低。

作者简介

本篇是“投稿达人” 张旭童 的第六篇投稿,今天给大家带来了炫酷的自定义动画按钮,希望大家喜欢。 

http://blog.csdn.net/zxt0601

概述

本文部分内容出自之前的博文(本文提及的上一节即指这篇)《酷炫Path动画》:

http://blog.csdn.net/zxt0601/article/details/54018970

今天给大家带来的是利用 纯自定义View,实现的仿饿了么加入购物车控件,自带闪转腾挪动画的按钮。效果图如下:

图1 项目中使用的效果,考虑到了 View 的回收复用,并且可以看到在 RecyclerView 中使用,切换 LayoutManager 也是没有问题的:

图2 Demo效果,测试各种属性值:

注意,本控件 非继承自ViewGroup,而是纯自定义View 实现。理由如下:

  • 1 减少布局层级,从而提高性能

  • 文字和图形纯draw,用到什么draw什么,没有其他的额外工作,也间接提高性能。

  • 纯自定义View难度更高,更有实(装)践(B)的意义

1. 减少布局层次,很好理解,ViewGroup 内嵌套几个 TextView、ImageView 这里写代码也可以实现这个效果,然而这会使布局层次多了一级,并且内部要嵌套多个控件,层级越多,控件越多,绘制的就越慢,在列表中对性能的影响更大。

2. 别小看了“小小”的 TextView 和 ImageView,其实它们有很多的属性和特性在本例中是不必要的,举个例子,查看源码,TextView 有一万多行,ondraw() 方法有一百多行, ImageView 有1588行,这么多行代码都是我们需要的吗?直接使用这些现成的控件嵌套实现,其实性能不如我们用到什么draw什么。唯一的好处可能就是比较简单了。(其实 TextView 的性能是不高的)

3. 纯自定义View,draw 出这些需要的元素,并且还要考虑动画,以及点击各区域的监听,实现起来还是有一些难度的,但我们多写一些有难度的代码才能提高水平。

如何使用

伸手党福利:讲解实现前,先看一下 如何使用 以及 支持的属性 等。

使用

xml:

注意:加减点击后,具体的操作,要根据业务的不同来编写了,设计到实际的购物车可能还有写数据库操作,或者请求接口等,要操作成功后才执行动画、或者修改count,这一块代码每个人写法可能不同。

使用时,可以重写 onDelClick() 和 onAddClick() 方法,并在合适的时机回调 onCountAddSuccess() 和 onCountDelSuccess() 以执行动画。效果图如 图2.

支持的属性

这么多属性够你用了吧。下面看重点的实现吧,Let’s Go!

实现解剖

关于自定义View的基础,这里不再赘述。如果阅读时有不明白的,建议下载源码边看边读,或者学习自定义View基础知识后再阅读本文。

我们捡重点说,无非是绘制。绘制的重点,这里分三块:

  • 静态绘制。(分两块:加减按钮和数量、hint提示文字和背景)

  • 第一层。(加减按钮和数量)以及它的旋转、位移、透明度动画

  • 第二层。(hint区域)以及它的伸展收缩动画

除了绘制以外的重点是:

  • 由于采用了完全的自定义View去实现这么一个“组合控件效果”,则点击事件的监听需要自己处理。

  • 回收复用的列表中使用时,列表滑动,如何正确显示UI。

静态绘制

静态绘制就是最基本的自定义View知识,绘制 圆圈(Circle)、线段(Line)、数字(Text) 以及 圆角矩形(RoundRect),值得注意的是,要考虑到 避免overDraw 和 动画的需求,我们要绘制的两层应该是互斥关系。

剥离掉动画代码,大致如下(基本都是draw代码,可以快速阅读):

根据 isHintMode 布尔值变量,区分是绘制 第二层(Hint层) 或者 第一层(加减按钮层)。

绘制 第二层 时没啥好说的,就是利用 canvas.drawRoundRect,绘制圆角矩形,然后 canvas.drawText 绘制 hint。(如果圆角的值足够大,矩形的宽度足够小,就变成了圆形。)

绘制 第一层 时,要根据当前的数量选择不同的颜色,注意在绘制加减按钮的圆圈时,我们是用 Path 绘制的,这是因为我们还需要用 Path 构建 Region类,这个类就是我们监听点击区域的重点。

点击事件的监听

在讲解动画之前,我们先说说如何监听点击的区域,因为本控件的动画是和加减数量息息相关的,而数量的加减是由点击相应”+ - 按钮”区域触发的。所以我们的监听按钮的点击事件,其实就是监听相应的”+ - 按钮”区域。

上一节 中,我们在绘制”+ - 按钮”区域时,通过 Path,构建了两个 Region类,Region类 有个 contains(int x, int y)方法如下,通过传入对应触摸的x、y坐标,就可知道知否点击了相应区域。

知道了这一点,再写这部分代码就相当简单了:

hint 模式时,我们可以认为控件所有范围都是“+”的有效区域。

而在 非hint 模式时,根据上一节构建的 mAddRegion 和 mDelRegion 去判断。

判断确认点击后,具体的操作,要根据业务的不同来编写了,设计到实际的购物车可能还有写数据库操作,或者请求接口等,要操作成功后才执行动画、或者修改count,这一块代码每个人写法可能不同。

使用时,可以重写 onDelClick() 和 onAddClick() 方法,并在合适的时机回调 onCountAddSuccess() 和 onCountDelSuccess() 以执行动画。

本文如下编写:

动画实现

这里会用到两个变量:

依次分析有哪些动画:

Hint动画

主要是圆角矩形的 展开、收缩。固定right、bottom,当展开时,不断减少矩形的左起点left坐标值,则整个矩形宽度变大,呈现展开。收缩时相反。代码:

减按钮动画

看起来是 旋转、位移、透明度。那么对于背景的圆圈来说,我们只需要位移、透明度。因为它本身是个圆,就不要旋转了。代码:

对于前景的“-”号来说,旋转、位移、透明度都需要做。这里我们利用 canvas.translate() canvas.rotate 做旋转和位移动画,别忘了 canvas.save()和 canvas.restore() 恢复画布的状态。(透明度在上面已经设置过了。)

数量的动画

看起来也是 旋转、位移、透明度。同样是利用canvas.translate() canvas.rotate 做旋转和位移动画。

动画的定义

动画是在View初始化时就定义好的,执行顺序:

  • 数量增加,0-1时,先收缩Hint(第二层)mAnimReduceHint执行,完毕后执行减按钮(第一层)进入的动画mAnimAdd。

  • 数量减少,1-0时,先执行减按钮退出的动画mAniDel,再伸展Hint动画mAnimExpandHint,完毕后,显示hint文字。

代码如下:

针对复用机制的处理

因为我们的购物车控件肯定会用在列表中,不管你用 ListView 还是 RecyclerView,都会涉及到复用的问题。

复用给我们带来一个麻烦的地方就是,我们要处理好一些属性状态值,否则UI上会有问题。可以从两处下手处理:

onMeasure

列表复用时,依然会回调 onMeasure()方法,所以在这里初始化一些UI显示的参数。这里顺带将适配 wrap_content 的代码也一同贴上:

在改变count时

一般在 onBindViewHolder() 或者 getView() 时,都会对本控件重新设置 count 值,count 改变时,当然也是需要根据 count 进行属性值的调整。且此时如果View正在做动画,应该停止这些动画。

总结

我在实现这个控件时,觉得难度相对大的地方在于做动画时,“-”按钮 和 数量的旋转动画,如何确定正确的坐标值。因为将text绘制的居中本身就有一些注意事项在里面,再涉及到动画,难免蒙圈。需要多计算,多试验

还有就是观察饿了么的效果,将hint区域的动画利用改变RoundRect的宽度去实现。起初没有想到,也是思考了一会如何去做。这是属于分析、拆解动画遇到的问题。

除了绘制以外的重点是:

  • 利用Region监听区域点击事件

  • 复用的列表,如何正确显示UI。

  • 动画次序以及考虑到复用时,在合适的地方取消动画

尽情在项目中使用它吧,有问题随时gayhub给我反馈。

通过sdk工具查看饿了么,它其实是用 TextView 和 ImageView 组合实现的。另外我十分怀疑它没有封装成控件,因为在列表页和详情页的交互,以及动画居然略有不同, 在详情页,仔细看由0-1时,它右边的 + 按钮的动画居然会闪一下,在列表页却没有,很是不解。

代码传送门:

https://github.com/mcxtzhang/AnimShopButton

更多

每天学习累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。

如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号: