ifelsething logoifelsething

Stop Scrolling at Regular Intervals in React Native

Published On: 2024-06-14
Posted By: Harish

Stop Scrolling at Regular Intervals in React Native

Generally, when content is scrolled, it scrolls till the momentum of the scrolling speed lasts. In some scenarios, we need to stop scrolling at regular intervals irrespective of the speed of the scroll.

In those situations, we can use snapToInterval prop to stop scroll at regular intervals of a value. This prop needs to be used with disableIntervalMomentum prop to stop the scroll momentum for intervals.

Let's see how it works with an example.

Create A New Project

Create a new react-native project by using npx. Check documentation for creating a new react native project.

npx react-native@latest init ScrollViewRN

Example Implementation

We will create a horizontal scrollview with few color blocks as a carousel and when scrolled, we will use the above props to stop at the next or previous color block.

Import and add ScrollView with some color blocks and horizontal orientation. Give a fixed width to color blocks. For now, I'm giving 200 as width.

//App.tsx
...
import { View, ScrollView } from 'react-native';
...
<ScrollView
  contentContainerStyle={{ alignSelf: 'flex-start' }}
  horizontal
>
  {
    colors
      .map((color: string) => {
        return (
          <View
            key={color}
            style={[
              styles.view,
              {
                backgroundColor: color
              }
            ]}
          >
          </View>
        )
      })
  }
</ScrollView>
...

If we run the app,

#for Android
npx react-native run-android

#for ios
npx react-native run-ios

We will see some scrollable horizontal color blocks and it will have a smooth scroll.

Stop Scrolling at Regular Intervals in React Native

Now add, snapToInterval prop with a value. Multiples of this value will be the stopping point for each scroll.

Above, we have given 200 as a width, so we'll stop scrolling at regular intervals of 200.

So, add snapToInterval={200}. We also need to add disableIntervalMomentum={true} to work correctly.

...
<ScrollView
  ...
  disableIntervalMomentum={true}
  snapToInterval={200}
>
...
</ScrollView>
...

Now, try to scroll as fast as you can, you will observe that the scrolling will stop at multiples of 200. This scroll can be viewed as x-axis and the values as x-coordinates.

No matter how fast you scroll, they will decelerate and stop at that interval. We can also use decelerationRate prop if you want.

Stop Scrolling at Regular Intervals in React Native

For better understanding, make the scrollview width as the width of each color block.

We can get the scrollview's width with onLayout callback which returns a size event on load.

So, add onLayout callback, get the scrollview width and apply it to the color block.

...
const [size, setSize] = useState<LayoutRectangle>();
...
<ScrollView
  ...
  snapToInterval={size?.width}
  onLayout={e => setSize(e.nativeEvent.layout)}
>
...
</ScrollView>
...

If we re-run the app, we can see that the color block fits perfectly to the width of the scrollview.

Now try to scroll as fast as you can. You will see that no matter how fast you scroll, it stops at the next color block and vice versa.

Stop Scrolling at Regular Intervals in React Native

Here, scrolling stops because the interval gets snapped to the edge. You can find more about snapping in snapToOffsets post.

Complete code of our example,

//App.tsx
import React, { useState } from "react";
import {
  Text,
  StyleSheet,
  SafeAreaView,
  StatusBar,
  View,
  ScrollView,
  LayoutRectangle,
} from "react-native";

const colors = [
  'orange',
  'green',
  'blue',
  'maroon',
  'violet',
  'darkorange',
  'gold',
  'darkgreen',
  'aquamarine',
  'cadetblue'
];

export default function App() {
  const [size, setSize] = useState<LayoutRectangle>();
  return (
    <SafeAreaView style={{ flex: 1, backgroundColor: 'white' }}>
      <StatusBar
        barStyle="dark-content"
      />
      <View style={styles.container}>
        <Text style={styles.text}>
          ifelsething.com
        </Text>
        <Text style={styles.text}>
          stop scrolling at regular intervals
        </Text>
        <ScrollView
          contentContainerStyle={{ alignSelf: 'flex-start' }}
          horizontal
          disableIntervalMomentum={true}
          snapToInterval={size?.width}
          onLayout={e => setSize(e.nativeEvent.layout)}
        >
          {
            colors
              .map((color: string) => {
                return (
                  <View
                    key={string}
                    style={[
                      styles.view,
                      {
                        backgroundColor: color,
                        width: size?.width || 200
                      }
                    ]}
                  >
                  </View>
                )
              })
          }
        </ScrollView>
      </View>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    margin: 10,
    gap: 20
  },
  text: {
    fontSize: 15,
    color: 'black',
    fontStyle: 'italic'
  },
  view: {
    height: 200,
    borderRadius: 10,
  }
});

Share is Caring

Related Posts