meliorence / react-native-snap-carousel

Swiper/carousel component for React Native featuring previews, multiple layouts, parallax images, performant handling of huge numbers of items, and more. Compatible with Android & iOS.
BSD 3-Clause "New" or "Revised" License
10.35k stars 2.29k forks source link

Snapping between items is very jerky #189

Open AdamPD opened 7 years ago

AdamPD commented 7 years ago

Hi guys,

I've searched around a lot and haven't found any information about this, but even the simplest of tests with the carousel I find are very jerky.

When swiping between items in the carousel, I notice that as soon as I release my finger, the speed of the snap changes. This means when I quickly flick to the next item, it instantly slows the snap speed so it looks like the swipe "hit a wall."

I'm tested this using Expo on an iPhone 7.

I've compared this to the native ScrollView with pagingEnabled or even snapToInterval and that has a much smoother effect.

Is this purely because the "snapping" action can't work out how much force a user swiped with? Or am I completely missing something?

I can probably put together an Expo snack to demonstrate the issue if need be.

bd-arc commented 7 years ago

1) You need to understand how the plugin works: it extends the FlatList component and, therefore, the ScrollView one. Unfortunately, and as described in the doc, there are many flaws and limitations with ScrollView's implementation. This means that we have to rely on workarounds and hacks to offer even the most basic features. For example, I would love to use snapToInterval but the scrollTo() method doesn't provide callbacks of any sort, and the prop is iOS only.

2) Never trust what you see in a debug environment. Make sure to build a production version of the app as this really smooths things out.

3) If you want to provide a momentum-based interaction, you can set prop enableMomentum to true.

4) I've never had any issue with nor complaints about carousel's behavior on iOS (Android is a different beast, which has been tamed recently). A screencast would definitely help me get a better understanding of the matter at stake.

5) I can use an Expo demo to let you know if what you're experiencing is to be expected.

eurobob commented 7 years ago

I'm also experiencing weird behaviour on iOS. It wasn't like this a few months ago. Not sure which version i had the best success with though, I will hunt it down and report back here

bd-arc commented 7 years ago

@eurobob This is strange, because I can't reproduce the issue.

Would you mind sharing a screencast or setting up an Expo example?

AdamPD commented 7 years ago

@bd-arc I'll try to put together a screencast. I also see this on the showcase application. Basically, the speed of the swipe versus the speed of the snap is different, so you get this moment of switching between the swipe and the snap.

I suppose this is the best we are going to get until react-native improves ScrollView etc.

eurobob commented 7 years ago

I thought I had already uploaded a screencast but it must not have gone through. Attaching it to this post instead carousel-jerk.zip

bd-arc commented 7 years ago

@AdamPD Thanks for describing the issue in greater details.

@eurobob Thank you for taking the time to put the screencast together! You said that a previous version of the plugin wasn't affected by the issue. I'm surprised, especially because @AdamPD experiences the issue even with the showcase app that uses version 1.4.0. Still, if you can figure out which version provided a better feeling, it would help tremendously.

Unfortunately, we don't have much control over ScrollView's behavior. Particularly, there is no way to specify a duration for the scrollTo() method. As you've properly understood, this means that we can't define a snap duration that would be consistent with the swipe gesture...

I'll see what I can do about implementing pagingEnabled and snapToInterval in order to improve things on iOS. Still, I'm afraid that it might mess with the callback mechanism (a hacky way to make up for the fact that scrollTo() doesn't provide any callback...).

Your input and suggestions are most welcome ;-)

AdamPD commented 7 years ago

@bd-arc - I tried to implement this iOS only using snapToInterval but I ran into major issues with left and right padding. If I used contentInsets it would not snap to the right position etc. Seems like potentially a react-native bug but I gave up and went with this instead.

JulianKingman commented 6 years ago

I have a similar issue (I think it's the same issue, just more pronounced), it seems to pause mid-transition (or as soon as touch is released), and is more pronounced when the carousel is released at the mid-point between slides. The closer to the middle, the more often it happens.

bd-arc commented 6 years ago

@JulianKingman I don't think that this is the same issue. The original one has to do with how velocity and momentum are handled, while yours looks like a performance issue.

Please open another issue with a reproductible example (take a look at the contributing guidelines) and I'll gladly take a look at it.

bd-arc commented 6 years ago

@AdamPD @eurobob This seems less of an issue with the new layouts I've introduced in version 3.6.0. What do you think?

Maybe it would be possible to create a custom interpolation that would compensate for the lack of velocity handling?

ikalangita commented 6 years ago

Hello, I tested today the carousel from the app https://itunes.apple.com/lu/app/archriss-presentation-mobile/id1180954376?mt=8, when swiping between item it's seems not very fluid, or it's desired? does increasing the speed will remove this jerky behaviour ?

bd-arc commented 6 years ago

@ikalangita The ScrollView component - on which the plugin is ultimately based - doesn't provide any way of handling momentum, speed, velocity and such, which is pretty unfortunate.

We've implemented a bunch of workarounds, but ultimately they are just poor substitutes for the missing features. Take a look at this note if you want to know more and to vote for RN's feature requests.

As a side note, the app you've tested uses version 1.4.0 of the plugin while the current version is 3.6.0; you will notice improvements with the latest versions.

ikalangita commented 6 years ago

Thank you for reply, i will test the new version then :), does example provided by the repo use this latest version?

bd-arc commented 6 years ago

@ikalangita Absolutely! Also make sure to try out the brand new layout prop; this is a pretty neat feature ;-)

JiboStore commented 6 years ago

@JulianKingman sorry, a bit oot, how do you achieve the full screen slider like your gif animation? I tried setting sliderWidth and itemWidth to `Dimensions.get('window').width; but seems like each item is a little bit more than the screen width, and the next item offset becomes wrong. After a few scroll I will then need one extra scroll to get to the next item...

Sorry, I found it in the documentation: https://github.com/archriss/react-native-snap-carousel/blob/master/doc/TIPS_AND_TRICKS.md#fullscreen-slides

I just need to add the extra: slideStyle={{ width: viewportWidth }} inactiveSlideOpacity={1} inactiveSlideScale={1}

JulianKingman commented 6 years ago

@JiboStore for reference, I just used itemWidth and sliderWidth, and had to be careful about using absolute positioning and flex sizing.

fotoflo commented 6 years ago

Hi, I have a similar issue, though the movement seems smooth, the snapping is not... Snappy.

https://www.youtube.com/watch?v=zlLHIGqNdOA

bd-arc commented 6 years ago

Hi @fotoflo,

Do you mean that the carousel doesn't snap to the desired position after releasing the touch?

If so, can you open a new issue including a Snack example that reproduces the problem?

fotoflo commented 6 years ago

hi @bd-arc, actually it snaps... just happening very slowly. Also it's offcenter.

Here in the snack it seems to work better... (still off center).

Could it be because my render function is getting called whenever the props are updating? (which happens about once a second due to a websocket interaction)

https://snack.expo.io/H1LOjtwPf

bd-arc commented 6 years ago

@fotoflo It's definitely not a plugin issue. My guess is that you've inadvertently activated the "Slow animations" feature of the iOS simulator (see the "Debug" menu).

Regarding slides' alignment, you made three mistakes:

Use the following and you'll be fine:

const ThumbnailBackgroundView = styled.View`
  width: 320; // same as `itemWidth`
  align-items: center;
`;
fotoflo commented 6 years ago

@bd-arc Thank you, excellent debugging job! works great 👍

fotoflo commented 6 years ago

Here's an updated example. I think it shows a few important things:

1) Styling 2) Handling onPress and onSnapToItem 3) Controlling the carousel with the ref.

https://snack.expo.io/@fotoflo/react-native-snap-carousel-example

I'm just a beginner, so there may be things you want to change, but please feel free to use it as a more complete example.

bd-arc commented 6 years ago

Thanks @fotoflo, but are you aware of the fact that there is already an example app that features this and much more ? ;)

Note that I will soon be able to work on adding a bunch of new examples. See #257 for more info.

fotoflo commented 6 years ago

Thanks @bd-arc I was aware. I took a look at that app and was lost pretty quickly (sorry, i'm more of a product manager than an engineer) .... here are my thoughts (from memory, if you don't mind).

zidniryi commented 5 years ago

help me how to use snap carraosel basic

ajaykumar97 commented 5 years ago

I am also facing the similar issue. I have placed the carousel absolutely positioned on the top of a MapView(react-native-maps) with custom markers inside the MapView. When I place the carousel below the map inside a View, the snapping is smooth. But when I place it on the top of the MapView, it has jerks while snapping from one item to another. However, without custom Markers, the snapping is smooth. I am using it something like:

...

<MapView
    ref={map => (this.map = map)}
    provider={PROVIDER_GOOGLE}
    region={this.state.region}
    style={{
        flex: 1
    }}
    customMapStyle={customMapStyle}
    loadingEnabled={true}
>
    {
     this.state.markers.map((marker, index) => {
      return (
        <Marker
            key={index}
            coordinate={{
                latitude: marker.latitude,
                longitude: marker.longitude
            }}
            image={icMarker}
        />
      );
     );
   }
</MapView>
   <View
        style={{
            position: 'absolute',
            bottom: 0
        }}
    >
        <Carousel
            ref={(c) => { this._carousel = c; }}
            data={this.props.data}
            activeSlideAlignment={'start'}
            inactiveSlideOpacity={1}
            renderItem={({ item, index }) => {
                return (
                    <ProductComponent
                        item={item}
                        index={index}
                    />
                );
            }}
            sliderWidth={size.width}
            itemWidth={((size.width * 2) / 3) - 20}
        />
    </View>

...

I am using:

"react": "16.6.3", "react-native": "0.57.8", "react-native-snap-carousel": "^3.7.5"

akhila-antony commented 4 years ago

@JulianKingman sorry, a bit oot, how do you achieve the full screen slider like your gif animation? I tried setting sliderWidth and itemWidth to `Dimensions.get('window').width; but seems like each item is a little bit more than the screen width, and the next item offset becomes wrong. After a few scroll I will then need one extra scroll to get to the next item...

Sorry, I found it in the documentation: https://github.com/archriss/react-native-snap-carousel/blob/master/doc/TIPS_AND_TRICKS.md#fullscreen-slides

I just need to add the extra: slideStyle={{ width: viewportWidth }} inactiveSlideOpacity={1} inactiveSlideScale={1}

This helps me to fix the flickering of carousel after the loop.This can also fix this issue:https://github.com/archriss/react-native-snap-carousel/pull/368

bd-arc commented 4 years ago

Smooth scrolling will finally be a reality in the next version.

Click here to learn everything about the upcoming v4!

16ntu1120 commented 3 years ago

@bd-arc if I set the autoplay prop to true thele animation is kind of fast that does not feel like it is animating but feels like only data in the card is changing. help needed

dohooo commented 3 years ago

Sorry, please allow me to advertise for my open source library! ~ I think this library react-native-reanimated-carousel will solve your problem. It is a high performance and very simple component, complete with React-Native reanimated 2