The React Native version of the React Native lottery wheel will be implemented from scratch

You can also use the React-Native super-Lottery component directly to develop the lottery feature.

A, layout,

The layout is simple and can be done with a flex 3-line layout or a single line with automatic line folding with the Flex-Wrap child control. Go straight to code

const LotteryStyle = StyleSheet.create({
  container: {
    flexDirection: 'row'.flexWrap: 'wrap'.justifyContent: 'center',}});const img_width = 100; // Width of the image
const img_height = 80; // Height of the image

// If you look at the turntable above, you will see that there are three types of palaces
// Currently highlighted cells (with a mask effect), normal functions, and center cells that can be clicked
// In a real situation, you would need to handle different grid effects according to the parameters item, index, highLightIndex, etc
// See the open source raffle component at the end of this article
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>  
Copy the code

Second, the animation

Next, we will focus on how to achieve the rotating table animation effect. After careful observation, we will find that the whole rotating table animation can be divided into three stages:

  1. Start of the draw: rotary speed up the spin phase
  2. Waiting for lottery result: Uniform rotation stage (may or may not, depending on the response speed of the back-end lottery interface)
  3. Turntable speed down stage, gradually stop to the prize grid

The acceleration and decay curves of the nine grids determine the smoothness of the turntable animation.

Implementation principle:

For the rotation of the turntable, setTimeout can be used to quickly modify the next highlighted grid, so as to achieve the visual effect of rotation

The rotation speed is actually the setTimeout interval. The greater the interval, the slower the rotation speed

Therefore, the smoothness of the rotary table animation actually depends on the continuity of setTimeout Interval changes

Scheme 1: Manual simulation of three stages

The general idea of the three stages of manual simulation is as follows:

  1. Before CYCLE_TIMES = 30 times, interval time decreases by 10ms each time, and the turntable accelerates gradually
  2. After 30 times, if no lottery result is returned, uniform rotation is performed to wait for the back end to return. If the result is returned, the third item is executed
  3. For the next eight times, the interval time increases by 20ms each time, and the speed of the turntable gradually decreases
  4. Speed minus 80ms before winning the lottery

The following pseudocode:

function startLottery() {
    this.setState({
        highLightIndex: currentIndex
    }, () => {
            this.currentIndex += 1;
            if (this.currentIndex > CYCLE_TIMES + 8 + this.uniformTimes && this.luckyOrder === currentOrder) {
                clearTimeout(this.lotteryTimer);
                // Complete the draw, display the prize popup, etc
            } else {
                if (this.currentIndex < CYCLE_TIMES) {
                    // CYCLE_TIMES = 30 times, speed increments 10ms,
                    this.speed -= 10;
                } else if (this.currentIndex > CYCLE_TIMES + 8 + this.uniformTimes && this.luckyOrder === currentOrder + 1) {
                    // Drop speed 80 before winning the lottery
                    this.speed += 80;
                } else if(this.luckyOrder) {
                    // The return result is uniform rotation
                    this.uniformTimes += 1;
                else {
                    this.speed += 20;
                }
                // Make sure the speed is not less than 50 ms
                if (this.speed < 50) {
                    this.speed = 50;
                }
                this.lotteryTimer = setTimeout(this.startLottery, this.speed); }}); }Copy the code

Scheme 2: Tween.js animation library

Tween.js is a JavaScript animation Tween library that allows you to smoothly change an object’s properties or a particular value. You just tell it what properties to change, what final values they should have when the tween finishes running, how long it takes or how many times, and the tween engine takes care of calculating the value that should be returned at any point in time from the start point to the end point.

Sounds exactly what we want. We can define three animation effects: Acceleration, constant speed and deceleration:

function animate() :void{
    TWEEN.update();
}

// Dial speed: the interval is reduced from an initial value of 100 (startup speed) to 40 (maximum dial speed) after 20 times
/ / the interval curve for TWEEN. Much. Quadratic. In
/ / about Tween. Js various numerical change curve can refer to https://sole.github.io/tween.js/examples/03_graphs.html here
const speedUpTween = new TWEEN.Tween({ interval: 100 })
    .to({ interval: 40 }, 20)
    .easing(TWEEN.Easing.Quadratic.In)
    .onUpdate((object) = > {
        // onUpdate every time the value changes, the callback can get the value of this interval, and then setTimeout starts animation
        setTimeout((a)= > {
            setHighLightIndex(highIndex + 1);
            animate();
        }, object.interval);
        currentSpeed = object.interval;
    })
    // The acceleration stage is completed and the constant speed stage is entered
    .onComplete((a)= > {
        speedUniformAnimate();
    })
    .start();

// Constant speed
function speedUniformAnimate() :void{
    setTimeout((a)= > {
        // If you do not get the result of the lottery, the wheel continues to rotate at a constant speed
        if (lotteryResult) {
            setHighLightIndex(highIndex + 1);
            speedUniformAnimate();
        } else {
            // Start decelerating after the constant speed phase
            speedDownTween.start();
        }
    }, currentSpeed);
}

// Deceleration from currentSpeed 40 to 500 after 8 decays
/ / the interval curve for TWEEN. Much. Quadratic. Out
const speedDownTween = new TWEEN.Tween({ interval: currentSpeed })
    .to({ interval: 500 }, 8)
    .easing(TWEEN.Easing.Quadratic.Out)
    .onUpdate((object) = > {
        setTimeout((a)= > {
            setHighLightIndex(highIndex + 1);
            animate();
        }, object.interval);
    });
Copy the code

There are two problems with the Demo above:

Because Tween animation must specify the target value, but in the deceleration phase, it may go through 8 decelerations and finally stop the position is not our winning grid position. Of course, we can reverse this problem by controlling the start time of the deceleration phase: in the constant motion phase, deceleration begins only when the lottery result is received and the winning position is still 8 Spaces away

The second problem is that if the turntable needs to support multiple lottery, speedUpTween, speedDownTween and other predefined animations need to be reinitialized. There is no similar method to reset in the official documentation, so we can only regenerate it temporarily.

The open source component React-Native clact-Lottery currently uses Scheme 1. Here provides a plan 2 simulation stage 3 Demo interested partners can imitate the implementation of a version of tween.js based animation.

After completing core functions such as layout and animation, it is easy for the encapsulated components to provide start, stop and other lottery functions. The detailed code can be referred to components such as React-Native – clacy-Lottery or directly used.