背景
最近继续学习编写Flutter,利用闲暇之余学了基本的动画、画布编写;个人认为animation和canvas对于前端来说还是非常重要的,毕竟我们是直面终端用户的,动画和画布能给我们的用户交互带来极大的加分。
除此之外,笔者Get到如何更好的学习编写自定义容器组件,其中主要实现了一个图片的拖拽缩放偏移容器的组件,但因为篇幅问题,自定义组件demo将会再下一篇文章展示。
Animation
Flutter的Animation已经封装的很不错了,其中有三个重要的对象:Animation、Tween、AnimationController。
Animation是一个抽象类,其对象通过lerp计算出动画实时变更的值;AnimationController管理Animation的整个过程,包括但不限于控制动画的状态,监听其动画值并且做出对应操作;Tween主要是提供动画值计算范围。
因此可看出,其实Animation本身跟UI渲染没有任何关系,只是提供动画的值。至于动画的值怎么跟UI进行绑定,动画完全不知道。因此整个动画的过程其实我们是可以非常明确掌控的,这是我认为Flutter动画中非常好的一点。
下面简单演示一下一个动画:购物车效果
1. 首先StatefulWidget需要mixin TickerProviderStateMixin,声明animation和animationController,通过Tween定义计算范围,并且为controller进行监听进而刷新界面。
2. 那么动画值如何跟UI绑定呢?先来看看我们的布局,通过Stack包裹布局,内部GirdView展示了多个子组件。当点击加入购物车的子组件时,Stack内会显示多一个购物车的布局,即shopCar();
购物车定位为:商品定位+(购物车定位-商品定位)*动画的值。在这里形成绑定。当然,也可以在controller中的listen中setState对应的值
3. 以上只是简单介绍动画的用法和逻辑,Tween理论上begin、end值可以+、-、*泛型T值都可以传递;此外,animation还实现了很多其他的非线性曲线动画,通过Curves类定义的很多曲线可以让动画以特定的曲线去变化,用法也非常简单:_animation =CurvedAnimation(parent:_animationController_03,curve: Curves.bounceIn);
4. 另外,Flutter内部还提供了很多UI组件,组件内部已经实现了对应的对话,一般只需要传入animationController即可。见下图:
更多animation组件可见官网:https://flutterchina.club/widgets/animation/
Canvas
1. 画布对于前端开发人员来说,也是能力考查的一个重要指标。Flutter Canvas主要继承CustomPainter,然后实现内部的paint和shouldRepaint,在paint里面画元素,在绘画之前需要先有一只画笔,也就是Paint(),然后根据canvas.drawXXX绘制对应的图形。下面代码主要是画一个圆弧:
2. Canvas 拥有多种绘制点、线、路径、矩形、圆形、以及添加图像的方法,结合这些方法我们可以绘制出千变万化的画面。同时Canvas 中有多个与绘制相关的方法,如drawLine()、drawRect()、drawOval()、drawOval()等方法。结合官网学习:https://book.flutterchina.club/chapter13/custom_paint.html
自定义组件
Flutter的组件多如牛毛,但作为前端,需要考虑到UI组件的复用性,同时又面对甲方以及项目经理的合理要求,难免要自己实现一些通用的组件。今天主要讲解一下一般自定义组件需要注意的点,算是对自己这段时间学习的一个总结吧。
1. 自定义组件需要继承什么类?一般来说,静态UI组件直接继承StatelessWidget,需要更新State的继承StatefulWidget。当然,笔者之前也继承过类似SampleDialog等Flutter组件,但其实也只是为了偷懒,想直接修改Flutter组件达到复用,但是可拓展性并不高,不建议这样做。
2. 组件视图如何更新?在调用组件时,可通过构造函数传递参数,参数可以是属性值也可以是callback方法。
对于StatefulWidget组件来说,很多时候需要更新UI,此时如果在组件外,即调用组件的文件中去通过callback方法setState组件内的变量,是会报上下文context错误的。因此这里需要使用监听的方式去实时updateUI,通过listen或者stream流的方式通知组件进行更新视图。
3. 如何做到组件内业务与界面分离?当自定义组件有太多的业务逻辑需要处理,特别是应用到矩阵计算或者动画的自定义组件,其业务逻辑是相对负责。笔者建议抽离出controller,将所有业务的抽离到一个controller class,作为必传属性传入自定义组件,自定义组件通过widget.controller.fun(),即可调用到逻辑方法。同时如需使用controller内部方法更新UI,可以参考上面第二点。
4. 我承诺,一周内把自定义组件demo的文章写完,此组件已经达到上线使用的效果,组件内部架构也比较合理。
为何写这篇文章?
记录学习。我所写的其实大都是非常基础的,但我认为对我个人思想、能力有较大提升的一些功能,我会把心得和经验记录下来,既能牢固知识,同时可希望可以跟大家一起学习探讨
希望大家多多指导我!