仿饿了么加入购物车控件

转载之
张旭童
本文部分内容出自之前的博文(本文提及的上一节即指这篇)《酷炫Path动画》:
http://blog.csdn.net/zxt0601/article/details/54018970

今天给大家带来的是利用 纯自定义View,实现的仿饿了么加入购物车控件,自带闪转腾挪动画的按钮。效果图如下:
**图1 **项目中使用的效果,考虑到了 View 的回收复用,并且可以看到在 RecyclerView 中使用,切换 LayoutManager 也是没有问题的:


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

注意,本控件 **非继承自ViewGroup,而是纯自定义View **实现。理由如下:
1 减少布局层级,从而提高性能

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

**3 **纯自定义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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容