前几天写了一个 Fluter 插件 tcard,用来实现类似于探探卡片的布局。
前言
前几天写了一个 Fluter 插件 tcard,用来实现类似于探探卡片的布局。效果如下,本文讲解如何使用 Stack
控件实现这个布局。
初识 Stack
Stack
是一个有多子项的控件,它会将自己的子项相对于自身边缘进行定位,后面的子项会覆盖前面的子项。通常用来实现将一个控件覆盖于另一个控件之上的布局,比如在一张图片上显示一些文字。子项的默认位置在 Stack
左上角,也可以用 Align
或者 Positioned
控件分别进行定位。
1 | Stack( |
Stack (Flutter Widget of the Week)
布局思路
要使用 Stack
实现这个卡片布局的大致思路如下
- 首先需要前,中,后三个子控件,使用
Align
控件定位在容器中。 - 需要一个手势监听器
GestureDetector
监听手指滑动。 - 监听手指在屏幕上滑动同时更新最前面卡片的位置。
- 判断移动的横轴距离进行卡片位置变换动画或者卡片回弹动画。
- 如果运行了卡片位置变换动画在动画结束后更新卡片的索引值。
卡片布局
- 创建
Stack
容器以及前,中,后三个子控件
1 | class MyApp extends StatefulWidget { |
- 对子控件分别定位并设置其尺寸
定位需要设置 Align
控件的 alignment 属性,传入一个 Alignment(x, y)
进行设置。设置尺寸需要使用 LayoutBuilder
获取当前父容器的尺寸,然后根据容器尺寸进行计算。
1 | class _MyAppState extends State<MyApp> { |
- 更新最前面卡片位置
向 Stack
容器添加一个 GestureDetector
,手指在屏幕上移动时更新最前面卡片的位置。
1 | class _MyAppState extends State<MyApp> { |
卡片动画
这个布局有三种动画,最前面卡片移开的动画;后面两张卡片位置和尺寸变化的动画;最前面卡片回到原位的动画。
- 判断卡片横轴移动距离
在手指离开屏幕时判断卡片横轴的移动距离,如果最前面的卡片横轴移动距离超过限制就运行换位动画,否则运行回弹动画。
1 | // 改变位置的动画 |
- 卡片回弹动画
首先实现卡片回弹的动画,使用 AnimationController
控制动画,在 initState
初始化动画控制器。创建一个 AlignmentTween
设置动画运动值,起始值是卡片当前位置,最终值是卡片的默认位置。然后将一个弹簧模拟 SpringSimulation
传递给动画控制器,让动画模拟运行。
1 | class _MyAppState extends State<MyApp> with TickerProviderStateMixin { |
- 卡片换位动画
卡片换位动画就是将最前面的卡片移除可视区,将中间的卡片移动到最前面,将最后的卡片移动到中间,然后新建一个最后面的卡片。在卡片更换位置的同时需要改变卡片的尺寸,位置动画和尺寸动画同时进行。首先定义每个卡片运动时的动画值
1 | /// 卡片尺寸 |
使用一个 AnimationController
控制动画运行,动画运行时在卡片上应用以上的动画值,否则使用卡片默认的位置和尺寸。
1 | class _MyAppState extends State<MyApp> with TickerProviderStateMixin { |
数据更新
可以看到动画运行之后三张卡片都恢复了默认的位置和尺寸,而需要的效果是当卡片换位动画完成后三张卡片的数据会改变,所以还需要在动画之后进行数据处理。
创建一个数组保存全部子项目,使用一个索引更新最前面卡片的子项索引,在卡片换位动画结束后索引值加一。
1 | List<String> images = [ |
至此整个布局就实现了 🎉
总结
这个布局的关键点在于
- 三张卡片的定位
- 监听手势更新最前面卡片的位置
- 卡片的换位动画和回弹动画
作者已经封装了这个插件,地址是 https://pub.dev/packages/tcard 欢迎使用。