今天推荐一个Github上比较有意思的关于翻页动画的项目,大致效果是这样的:
仓库地址是:https://github.com/matthew-carroll/flutter_ui_challenge_material_page_reveal
作者的实现思路很清晰,代码结构设计的非常合理,有很多值得学习的地方,让我们来做对代码个简单的分析。
main.dart中的MyHomePage是界面的主入口,
结构很清晰,Page是指最底层的页面,PageReveal指手指左右滑动后出现的上层页面,PagerIndicator是指页面底部的页码指示器,最后是PageDragger,用于接收用户的滑动事件。
Page
上图同时也展示了构造这几种对象所需要的关键元素,Page信息主要通过一个PageViewModel的类来进行描述:
color是界面的背景色,heroAssetPath用来引用页面中心的图片,title和body都是指页面中出现的文本,iconAssetPath是底部页面指示器中显示的icon。除此之外Page构造函数还接收一个percentVisible参数,代表页面切换进度的百分比,仔细观察的话可以看到页面切换过程中页面中心的图片和文本有一个轻微的透明度和位置的变化,例如图片的位置移动是在这里实现的:
PageReveal
PageReveal是对Page进行裁剪得来的,上图中可以看到构造函数中child参数传入了一个Page对象,PageReveal对child做了什么操作呢,来看一下:
根据需要露出的百分比revealPercent对child进行裁剪,虽然这里的Rect.fromLTWH导致getClip方法返回的是一个矩形,但是外层有一个ClipOval的包裹,保证了最后输出的图形是一个圆形。
PagerIndicator的显示逻辑相对要复杂一点,要根据一定的规则对图标进行缩放和颜色切换,同时伴随透明度的变化。代码中通过PageBubbleViewModel类来描述指示器中的一个圆点:
isHollow表示圆点对应的页码是否大于当前页码,如果大于的话显示空心,否则显示实心。
这段代码包含了控件大小、透明度、是否实心等参数的计算。
PagerIndicator的build函数主要工作就是根据page数组生成PageBubble列表,并添加到一个Column中:
PageDragger
最后再来看一下PageDragger,主要用来接收触摸事件,对事件经过一定的加工后传送到_MyHomePageState中来做界面绘制参数的整体的调度。传送的方式是通过StreamController来实现的。Flutter中的StreamController主要是用于异步事件的发送和接收,官方文档请移步这里,阅读之前最好看下相关概念Stream。本质上还是要实现一个生产者消费者模型,通过StreamController的add方法来发出事件,listen方法实现监听和消费事件。设计理念和React概念类似,有一个Rxdart库也是基于Stream相关的API来实现的,有兴趣的可以了解一下。
page_dragger.dart文件中还声明了另外一个类AnimatedPageDragger ,用于实现滑动结束后的动画。因为用户的手指松开后,上层的Page可能还没又完全覆盖底层,那么根据手指离开时覆盖的百分比,大于0.5则完成后续的翻页动作,否则要恢复之前的操作,上层的Page要有一个逐渐缩小的动画,这两种情况是通过枚举TransitionGoal来区分,其中open表示继续打开,close则是恢复手指滑动前的原状。动画过程中的参数变化通过AnimationController来实现,根据时间的流逝来计算绘制所需的参数,并通过StreamController传送到_MyHomePageState中,然后修改成员变量slidePercent和slideDirection,来影响界面中不同控件的绘制参数,从而实现动画效果。
Flutter程序员公众号,关注Flutter相关话题~
网友评论