一、本文实现的九宫格抽奖动画效果如下
二、主要分享下怎么一步一步来实现这个效果
源代码地址
布局可以通过GridView
轻松实现,只需在数据源的第五个位置插入一个元素用来标识是开始按钮抽奖动画的实现,需要按顺时针循环选中奖品而且还需要从慢—>快—>慢
的效果抽奖按钮的缩放动画(这个比较简单)最后动画停止在设定的奖品位置上三、实现抽奖UI布局
这里每个item
要区分是奖品还是开始按钮@overrideWidget build(BuildContext context) {return GridView.builder(itemCount: widget.list.length,padding: EdgeInsets.zero,gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3,mainAxisSpacing: 18,crossAxisSpacing: 18,childAspectRatio: 1,),physics: const NeverScrollableScrollPhysics(),itemBuilder: (_, index) {///构建每个奖品 和 开始抽奖按钮return _buildItem(widget.list[index], index);},);}
最重要的动画实现,这里可以使用StepTween
动画给定一个begin, end最终会返回[begin,end]
区间内的整数序列,这样就可以依次选中每一个奖品
void _initAnimation() {_controller = AnimationController(vsync: this,duration: const Duration(milliseconds: 5500),);_animation = StepTween(begin: 0, end: 8).animate(CurvedAnimation(parent: _controller, curve: Curves.ease),);}
1、最终在item上使用
AnimationBuilder
进行动画监听,就可以时时获取当前选中的奖品下标。2、上面说了需要实现从
慢—>快—>慢
的效果:只需要给动画设置个curve
插值器即可,flutter已经为我们提供了许多种效果,具体查看Curves
类即可。上面使用到的Curves.ease
便是这种效果
3、 关键问题怎么实现顺时针旋转呢?
上面已经通过动画可以产生[0,8]内的整数了,所以只需要和那个8个奖品item对应即可,如下:
旋转的顺序为:0—>1—>2—>5—>8—>7—>6—>3 所以通过如下转换即可实现
int get _animationIndex {return [0, 1, 2, 5, 8, 7, 6, 3][_animation.value % 8];}
4、 最后一步,怎么让动画停在中间的奖品上?
从上面分析可以轻松的知道给定[0,8]最终动画执行完会回到
0
第一个奖品处,所以如果想落在某一个上只需要知道奖品离第一个奖品需要几步
。假设需要抽中iPad
,则需要3步,所以只需要在初始动画给定end的时候加上这个数值即可
void _initAnimation() {_controller = AnimationController(vsync: this,duration: const Duration(milliseconds: 5500),);_animation = StepTween(begin: 0, end: 8 + 3).animate(CurvedAnimation(parent: _controller, curve: Curves.ease),);}