Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FlatList snapToInterval is not precise in long list #21441

Closed
chicken-suop opened this issue Oct 1, 2018 · 28 comments
Closed

FlatList snapToInterval is not precise in long list #21441

chicken-suop opened this issue Oct 1, 2018 · 28 comments
Labels
Bug Component: FlatList Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@chicken-suop
Copy link

Environment

Environment:
OS: macOS 10.14
Node: 8.12.0
Yarn: Not Found
npm: 6.4.1
Watchman: 4.9.0
Xcode: Not Found
Android Studio: 3.2 AI-181.5540.7.32.5014246

Packages: (wanted => installed)
react: 16.3.1 => 16.3.1
react-native: https://github.com/expo/react-native/archive/sdk-29.0.0.tar.gz => 0.55.4

Description

I'm using the FlatList component with around 50 elements. When my element height (and subsequently snapToInterval prop) are set to floats, rather than integers, there seems to be a proportionality increasing offset from the correct interval to snap to. The affect of this is very noticeable with a lot of elements. The further I scroll down a list the bigger the offset, so that when I get to the bottom, it's very noticeable.

This offset is still there with integers, but it's a lot less pronounced.
Screenshots:

First two are with height set to 105.14285714285714, which is an iPhone 6s Plus' height divided by seven. The last two have height set to 105, which is just the truncated version of the previous height.

Height: 105.14285714285714 (at bottom):
105 14285714285714 at bottom

Height: 105.14285714285714 (second from top):
105 14285714285714 second from top

Height: 105 (at bottom):
105 at bottom

Height: 105 (second from top):
105 second from top

Reproducible Demo

https://snack.expo.io/@elliotschep/flatlist-snaptointerval-is-not-precise-in-long-list

@mjmasn
Copy link
Contributor

mjmasn commented Oct 9, 2018

There is a similar issue on Android and horizontal ScrollView with devices like the Nexus 5X which apparently has a screen width of 411.428571429dp (wtf?), both with pagingEnabled and with integer intervals you can see the rounding errors creeping up as you scroll further along the view. On devices with integer screen width there is no problem.

@stale
Copy link

stale bot commented Jan 20, 2019

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jan 20, 2019
@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Jan 24, 2019
@hramos hramos removed the Bug Report label Feb 6, 2019
@ElChurros
Copy link

Hi,

I am experiencing the exact same issue on my end with react native 0.59.9. Have you guys found a workaround since you posted this issue in october @ratskin @mjmasn ?

@chicken-suop
Copy link
Author

Not me. I had to change my UI to account for this

@stale
Copy link

stale bot commented Oct 2, 2019

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Oct 2, 2019
@mjmasn
Copy link
Contributor

mjmasn commented Oct 2, 2019

stale bot, this is still an issue as far as I know

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Oct 2, 2019
@sharma0611
Copy link

I'm also having this issue as well

@sharma0611
Copy link

To anyone else facing this: I got around this issue by using snapToOffsets to achieve the same effect.

@Amalgatito
Copy link

Having the same issue!

@ttaallll
Copy link

To anyone else facing this: I got around this issue by using snapToOffsets to achieve the same effect.

snapToOffsets solved it for me too.

I just calculated the stops of the next snap by the number of items and the margin between them.

for example:

const { width } = Dimensions.get('window');
this.IMAGE_WIDTH = width * (1 / 2.5)
this.image_margin = 5
this.nishhar = width - ((this.IMAGE_WIDTH + this.image_margin) * 2 + this.image_margin * 2)

dataNum = [1, 2, 3, 4, 5, 6]

return (<FlatList
            data={dataNum}
            renderItem={item => {
                return (
                    <View style={{
                        backgroundColor: item.index % 2 == 0 ? 'red' : 'blue',
                        width: this.IMAGE_WIDTH,
                        height: this.IMAGE_WIDTH,
                        marginLeft: this.image_margin,
                        marginRight: this.image_margin,
                    }}>
                    </View>)
            }}
            keyExtractor={this.keyGenerator}
            horizontal={true}
            snapToAlignment={"start"}
            snapToOffsets={[...Array(dataNum.length)].map((x, i) => (i * (this.IMAGE_WIDTH + 2 * this.image_margin) - (this.nishhar * 0.5)))}
            decelerationRate={"fast"}
            pagingEnabled
        />)

@stale
Copy link

stale bot commented Mar 17, 2020

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Mar 17, 2020
@mjmasn
Copy link
Contributor

mjmasn commented Mar 18, 2020

not stale

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Mar 18, 2020
@stale
Copy link

stale bot commented Jun 17, 2020

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jun 17, 2020
@enheit
Copy link

enheit commented Jun 23, 2020

not stale

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Jun 23, 2020
@chicken-suop
Copy link
Author

@ttaallll I believe I also solved it like this. I haven't measured it, but I'd think you'd take a hit in performance (especially for large data sources), so I wouldn't consider this a final solution.

@ayalfishey
Copy link

Still an issue

@adamsolomon1986
Copy link

To anyone else facing this: I got around this issue by using snapToOffsets to achieve the same effect.

snapToOffsets solved it for me too.

I just calculated the stops of the next snap by the number of items and the margin between them.

for example:

const { width } = Dimensions.get('window');
this.IMAGE_WIDTH = width * (1 / 2.5)
this.image_margin = 5
this.nishhar = width - ((this.IMAGE_WIDTH + this.image_margin) * 2 + this.image_margin * 2)

dataNum = [1, 2, 3, 4, 5, 6]

return (<FlatList
            data={dataNum}
            renderItem={item => {
                return (
                    <View style={{
                        backgroundColor: item.index % 2 == 0 ? 'red' : 'blue',
                        width: this.IMAGE_WIDTH,
                        height: this.IMAGE_WIDTH,
                        marginLeft: this.image_margin,
                        marginRight: this.image_margin,
                    }}>
                    </View>)
            }}
            keyExtractor={this.keyGenerator}
            horizontal={true}
            snapToAlignment={"start"}
            snapToOffsets={[...Array(dataNum.length)].map((x, i) => (i * (this.IMAGE_WIDTH + 2 * this.image_margin) - (this.nishhar * 0.5)))}
            decelerationRate={"fast"}
            pagingEnabled
        />)

thank you so much for sharing....this was the only thing that worked for me.

@Crael94
Copy link

Crael94 commented Dec 20, 2021

To anyone else facing this: I got around this issue by using snapToOffsets to achieve the same effect.

snapToOffsets solved it for me too.

I just calculated the stops of the next snap by the number of items and the margin between them.

for example:

const { width } = Dimensions.get('window');
this.IMAGE_WIDTH = width * (1 / 2.5)
this.image_margin = 5
this.nishhar = width - ((this.IMAGE_WIDTH + this.image_margin) * 2 + this.image_margin * 2)

dataNum = [1, 2, 3, 4, 5, 6]

return (<FlatList
            data={dataNum}
            renderItem={item => {
                return (
                    <View style={{
                        backgroundColor: item.index % 2 == 0 ? 'red' : 'blue',
                        width: this.IMAGE_WIDTH,
                        height: this.IMAGE_WIDTH,
                        marginLeft: this.image_margin,
                        marginRight: this.image_margin,
                    }}>
                    </View>)
            }}
            keyExtractor={this.keyGenerator}
            horizontal={true}
            snapToAlignment={"start"}
            snapToOffsets={[...Array(dataNum.length)].map((x, i) => (i * (this.IMAGE_WIDTH + 2 * this.image_margin) - (this.nishhar * 0.5)))}
            decelerationRate={"fast"}
            pagingEnabled
        />)

Thanks !

I don't know why but for my case I had to remove and don't use the nishhar variable.

@ValentineCodes
Copy link

To anyone else facing this: I got around this issue by using snapToOffsets to achieve the same effect.

snapToOffsets solved it for me too.

I just calculated the stops of the next snap by the number of items and the margin between them.

for example:

const { width } = Dimensions.get('window');
this.IMAGE_WIDTH = width * (1 / 2.5)
this.image_margin = 5
this.nishhar = width - ((this.IMAGE_WIDTH + this.image_margin) * 2 + this.image_margin * 2)

dataNum = [1, 2, 3, 4, 5, 6]

return (<FlatList
            data={dataNum}
            renderItem={item => {
                return (
                    <View style={{
                        backgroundColor: item.index % 2 == 0 ? 'red' : 'blue',
                        width: this.IMAGE_WIDTH,
                        height: this.IMAGE_WIDTH,
                        marginLeft: this.image_margin,
                        marginRight: this.image_margin,
                    }}>
                    </View>)
            }}
            keyExtractor={this.keyGenerator}
            horizontal={true}
            snapToAlignment={"start"}
            snapToOffsets={[...Array(dataNum.length)].map((x, i) => (i * (this.IMAGE_WIDTH + 2 * this.image_margin) - (this.nishhar * 0.5)))}
            decelerationRate={"fast"}
            pagingEnabled
        />)

This improved my experience. Thanks!

@AhmedAbuelenin
Copy link

AhmedAbuelenin commented Jan 16, 2023

Still facing this issue with RN 0.70.6 .I used @ttaallll workaround, thank you.

@rjdestigter
Copy link

Encountered the same issue on horizontal list with 1000 items of the same width. Switching to snapToOffset resolved this for me as well. The odd part was that the issue only occured when the FlatList component's width was less than the device width and only on Android devices.

Giving the component a fixed width (to avoid the floating point widths) also didn't resolve the issue. Setting initialScrollIndex to 0 rather than 500 (half the data size) did seem to resolve the issue but I do wonder if the problem would show up if I scrolled enough.

@garrettg123
Copy link

I'm finding this to only be an issue when setting a custom windowSize={3} to improve performance. When I remove that, the snapToInterval={theme.space[4] + itemWidth} works perfectly. Problem is that windowSize improves performance significantly.

@thanhnd1o2
Copy link

thanhnd1o2 commented May 23, 2023

I found in native code that the type of snapToInterval is int (/node_modules/react-native/React/Views/ScrollView/RCTScrollView.h). Therefore, every Float value from JS will be cast as int.
I modified type of snapToInterval to Float64 and it worked like a charm

@jencircj-developer
Copy link

Same issue exist's for me too in some android devices. It happens for my vertical posts (Full device height) inside FlatList. Although the workaround mentioned above fixed the issue but now there is black margin of 5 pixels appearing in between the posts which makes my UI a bit odd. Would be good if this issue get's fixed in a proper way.

@reckziegelwilliam
Copy link

Bump

Copy link

github-actions bot commented Apr 8, 2024

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Apr 8, 2024
Copy link

This issue was closed because it has been stalled for 7 days with no activity.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Apr 16, 2024
@himanshut230
Copy link

Still facing this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Component: FlatList Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests