1

我正在尝试在 react-native 上制作一些简单的动画。我正在使用react-native-canvas,它似乎很好地实现了普通的 html 画布,但我在真实设备上得到了一些可怕的闪烁。我在 iOS 模拟器上几乎没有闪烁,但 Android 模拟器很糟糕。

我当前的代码已经实现了我发现的以下建议:

  • 利用requestAnimationFrame
  • 双缓冲
  • 帧率处理
  • 避免对变量使用状态(因为它们会重新触发渲染)

我的目标是制作不闪烁的动画。我不介意在较慢的设备上播放速度较慢但闪烁对用户来说不是一种好感觉。

我做错了什么?

这是代码:

initTempCanvas = (canvas) => {
    if (canvas !== null) {
        canvas.width = this.window_size.height;
        canvas.height = this.window_size.width + 50;
        this.tempCanvas = canvas;
        this.tempCtx = canvas.getContext('2d');
        canvas.hidden = true;
    }
}

initCanvas = (canvas) => {
    if (canvas !== null) {
        var fps = 25;
        this.interval = 1000 / fps;
        this.speed = 30;
        // These are switched because of landscape mode
        canvas.width = this.window_size.height;
        canvas.height = this.window_size.width + 50;
        this.canvas = canvas;
        this.ctx = canvas.getContext('2d');

        requestAnimationFrame(this.drawLoop);
    }
}

drawLoop = (now) => {
    if (this.tempCtx !== undefined) {
        if (!this.then) {
            this.then = now;
        }
        this.delta = now - this.then;

        if (this.delta > this.interval) {
            this.ctx.save();
            this.tempCtx.clearRect(0, 0, this.tempCanvas.width, this.tempCanvas.height)

            this.drawCircle(this.tempCtx, (this.canvasTimer * 100), this.tempCanvas.height / 2 + (-125 * Math.sin(this.canvasTimer * (Math.PI / 2) - Math.PI * 0.5)), 30, 'purple', 'purple', 2);

            this.ctx.drawImage(this.tempCanvas, 0, 0);
            this.ctx.restore();
            this.deltaTime = this.delta / 100000 * this.speed;
            this.canvasTimer += this.deltaTime;
        }
        this.then = now - (this.delta % this.interval);
    }
    requestAnimationFrame(this.drawLoop);
}

drawCircle = (ctx, x, y, radius, fill, stroke, strokeWidth) => {
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
    if (fill) {
        ctx.fillStyle = fill;
        ctx.fill();
    }
    if (stroke) {
        ctx.lineWidth = strokeWidth;
        ctx.strokeStyle = stroke;
        ctx.stroke();
    }
}

render() {
    return (
        <View>
            {this.tempCanvas == undefined && <Canvas ref={this.initCanvas} />}
            <Canvas style={"display: none"} ref={this.initTempCanvas} />
        </View>
    )
}

4

0 回答 0