31

I want to to a horizontal ScrollView with pagination enabled with one special requirement: each page (or card) is 90% of the container wide. The remaining 10% should be a preview of the next page.

It is possible to do this with ScrollView? Can I somehow specify the width of the pagination instead of taking the width of the container?

Carousel (image taken from this similar question: React Native Card Carousel view?)

Community
  • 1
  • 1
Johannes Filter
  • 1,863
  • 3
  • 20
  • 25

6 Answers6

46

I spend a lot of time fighting with this until I figured it out so here is my solution if it helps someone.

https://snack.expo.io/H1CnjIeDb

Problem was all these were required and pagination should be turned off

horizontal={true}
decelerationRate={0}
snapToInterval={width - 60}
snapToAlignment={"center"}
Vasil Enchev
  • 1,656
  • 15
  • 18
34

You can absolutely do that with ScrollView or, even better, FlatList. However, the really tricky part is the snapping effect. You can use props snapToInterval and snapToAlignment to achieve it (see Vasil Enchev's answer); unfortunately, these are iOS-only.

A co-worker and I created a plugin that answers this particular need. We ended up open-sourcing it, so it's all yours to try: react-native-snap-carousel.

The plugin is now built on top of FlatList (versions >= 3.0.0), which is great to handle huge numbers of items. It provides previews (the effect you're after), snapping effect for iOS and Android, parallax images, RTL support, and more.

You can take a look at the showcase to get a grasp of what can be achieved with it. Do not hesitate to share your experience with the plugin since we're always trying to improve it.

react-native-snap-carousel archriss showcase react-native-snap-carousel archriss aix


Edit : two new layouts have been introduced in version 3.6.0 (one with a stack of cards effect and the other with a tinder-like effect). Enjoy!

react-native-snap-carousel stack layout react-native-snap-carousel tinder layout

bend
  • 1,384
  • 14
  • 22
  • 1
    @AlfredAlfizoMosima Sure ;-) [Here is](https://snack.expo.io/@akyker20/react-native-snap-carousel-bug) a simple example. – bend Jun 09 '18 at 20:07
  • trying to achieve something similar but with recyclerlistview.. FlatList has too many issues for me.. – Timur Ridjanovic May 29 '20 at 00:04
  • You're awesome guys.. Thanks for this great component. I was stuck with flatlist trying to get the current active item index for some animation related stuff. I tried all day but it was failing for large data sets. Snap Carousal gave perfect results. Thanks again. – Yehya Apr 30 '21 at 13:39
13

Use disableIntervalMomentum={ true } in your ScrollView. This will only allow the user to scroll one page at a time horizontally. Check official documents https://reactnative.dev/docs/scrollview#disableintervalmomentum

 <ScrollView 
  horizontal
  disableIntervalMomentum={ true } 
  snapToInterval={ width }
 >
  <Child 1 />
  <Child 2 />
</ScrollView>
Mohit Goel
  • 722
  • 1
  • 8
  • 18
4

You can pass a horizontal props to your scroll view:

https://facebook.github.io/react-native/docs/scrollview.html#horizontal

And then you can create a view inside to specify your width requirements.

<ScrollView 
  ref={(snapScroll) => { this.snapScroll = snapScroll; }}
  horizontal={true} 
  decelerationRate={0}
  onResponderRelease={()=>{

   var interval = 300; // WIDTH OF 1 CHILD COMPONENT 

   var snapTo = (this.scrollingRight)? Math.ceil(this.lastx / interval) : 
    Math.floor(this.lastx / interval);
   var scrollTo = snapTo * interval;
   this.snapScroll.scrollTo(0,scrollTo);
  }}
  scrollEventThrottle={32}
  onScroll={(event)=>{
    var nextx = event.nativeEvent.contentOffset.x;
    this.scrollingRight = (nextx > this.lastx);
    this.lastx = nextx;
  }}
  showsHorizontalScrollIndicator={false} 
  style={styles.listViewHorizontal}
  >

  {/* scroll-children here */}

</ScrollView>
Gabriel Mesquita
  • 2,271
  • 1
  • 20
  • 30
  • I have `horizontal={true} pagingEnabled={true}` as props in the ScrollView. But the "scroll view stops on multiples of the scroll view's size when scrolling" https://facebook.github.io/react-native/docs/scrollview.html#pagingenabled – Johannes Filter Apr 04 '17 at 17:07
  • Also see this issue for help https://github.com/facebook/react-native/issues/1362 – Gabriel Mesquita Apr 04 '17 at 17:23
2

Here is example of simple scrollview pagination for bottom:

<ScrollView
......
onMomentumScrollEnd={event => {
   if (isScrollviewCloseToBottom(event.nativeEvent)) {
      this.loadMoreData();
   }
}}
</ScrollView>

.....
....

function isScrollviewCloseToBottom({
  layoutMeasurement,
  contentOffset,
  contentSize,
}) {
  const paddingToBottom = 20;
  return (
    layoutMeasurement.height + contentOffset.y >=
    contentSize.height - paddingToBottom
  );
}

......
....

same as we can use this for right pagination:

function isScrollviewCloseToRight({
  layoutMeasurement,
  contentOffset,
  contentSize,
}) {
  const paddingToRight = 10;
  return (
    layoutMeasurement.width + contentOffset.x >=
    contentSize.width - paddingToRight
  );
}

Hope it will helpful..!!

Pankaj bhalala
  • 163
  • 1
  • 11
0

You can look at contentOffset and scrollTo property of ScrollView . Logically what you can do is whenever the page changes(mostly when moved to next page) you can provide a extra offset of 10% or so as per your need so that the next item in the scrollview becomes visible .

Hope this helps, let me know if you need any extra details .

Abhinandan Sahgal
  • 1,076
  • 1
  • 13
  • 27