本文将介绍从零开始实现一个 React Native 版本的九宫格抽奖转盘,先看最终效果图
也可以直接使用react-native-super-lottery组件开发抽奖功能。
一、布局
布局很简单,我们可以采用flex 3行布局,也可以单行、配合flex-wrap子控件自动折行实现。直接上代码
const LotteryStyle = StyleSheet.create({
container: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
}
});
const img_width = 100; // 图片的宽度
const img_height = 80; // 图片的高度
// 观察上图的转盘,会发现存在三种类型的宫格
// 当前被高亮的宫格(增加了蒙层效果) , 正常的功能,以及正中心可以被点击的宫格
// 在真实的情况里,就需要根据 item、 index、 highLightIndex 等参数处理不同的宫格效果
// 具体可以参考本文最后开源的抽奖组件
function renderItem(item, index, highLightIndex) {
const { url } = item;
return <Image style={
{ width, height }} source={
{ uri: url }}/>;
}
<View style={LotteryStyle.container}>
{
data.map((item, index) => {
return renderItem(item);
})
}
</View>
动画
接下来重点介绍如何实现转盘动画效果,仔细观察会发现整个转盘动画可以分为三个阶段:
- 抽奖开始:转盘加速旋转阶段
- 等待抽奖结果:匀速旋转阶段(可能有、可能无,根据后端抽奖接口响应速度决定)
- 转盘降速阶段,逐步停到中奖宫格
九宫格的加速和衰减曲线决定了转盘动画的流畅程度。
实现原理:
转盘的转动,可以采用 setTimeout 快速修改下一个应该高亮的宫格,从而达到转动的视觉效果
旋转的速度其实就是 setTimeout 的interval间隔,interval越大速度越慢
因此转盘动画的流畅程度实际取决于 setTimeout interval 值变化的连续性
方案一:手动模拟三个阶段
手动模拟三个阶段大体思路如下:
- 前 CYCLE_TIMES = 30 次, 每次interval time 递减10ms,转盘逐渐加速
- 30次后如果没有返回了抽奖结果,则执行匀速旋转等待后端返回,如果返回了结果执行第三条
- 之后 8 次每次interval time 递增20ms,转盘逐渐降速
- 中奖前一次速度减80ms
下面的伪代码:
function startLottery() {
this.setState({
highLightIndex: currentIndex
}, () => {
this.currentIndex += 1;
if (this.currentIndex > CYCLE_TIMES + 8 + this.uniformTimes && this.luckyOrder === currentOrder) {
clearTi