Flipkart / recyclerlistview

High performance listview for React Native and web!
Apache License 2.0
5.21k stars 426 forks source link

Animated Scroll performance issues on low performance devices #277

Open ejbp opened 5 years ago

ejbp commented 5 years ago

I'm facing several animated scroll performance issues on low performance devices. I noticed that on ScrollViewer.prototype._doAnimatedScrollfunction on platform/web/scrollcomponent/ScrollViewer.js file you're using setTimeout instead of window.requestAnimationFrame . Please consider to change it. I'm happy to do a PR if you want.

Current:

private _doAnimatedScroll(offset: number): void {
        let start = this._getRelevantOffset();
        if (offset > start) {
            start = Math.max(offset - 800, start);
        } else {
            start = Math.min(offset + 800, start);
        }
        const change = offset - start;
        const increment = 20;
        const duration = 200;
        const animateScroll = (elapsedTime: number) => {
            elapsedTime += increment;
            const position = this._easeInOut(elapsedTime, start, change, duration);
            this._setRelevantOffset(position);
            if (elapsedTime < duration) {
                window.setTimeout(() => animateScroll(elapsedTime), increment);
            }
        };
        animateScroll(0);
    }

Suggestion:

private _doAnimatedScroll(offset: number): void {
        let start = this._getRelevantOffset();
        if (offset > start) {
            start = Math.max(offset - 800, start);
        } else {
            start = Math.min(offset + 800, start);
        }
        const change = offset - start;
        const duration = 200;
        let elapsedTime = 0;
        let lastRenderTimestamp: number = -1;
        const animateScroll = (timestamp: number) => {

            if ( lastRenderTimestamp === -1 ) {
                lastRenderTimestamp = timestamp - 20; //in order to immediately jump to 1st frame
            }

            const deltaTime = timestamp - lastRenderTimestamp;
            lastRenderTimestamp = timestamp;
            elapsedTime = Math.min ( elapsedTime + deltaTime, duration );

            const position = this._easeInOut(elapsedTime, start, change, duration);
            this._setRelevantOffset(position);
            if (elapsedTime < duration) {
                window.requestAnimationFrame(animateScroll);
            }
        };
        window.requestAnimationFrame(animateScroll);
    }
naqvitalha commented 5 years ago

Yes, that's a poor implementation. I'd be happy to pull in a fix.

arunreddy10 commented 4 years ago

@ejbp We would be happy to pull in a fix. Feel free to raise a PR

RameshkrishnanV commented 3 years ago

Any update on this issue?