0

I'm new with react native, and I found the Animated in react-native, so there is a carousel with images. I can just swipe it horizontally, but I want it also can auto scroll by default.. and when it becomes to last slider it should starts from first slider with animations.. please help me out the solution, thank you very much!

Carousel.js (shared code here - https://codeshare.io/G8EZOZ):

import React, { useCallback, useEffect, useRef, useState } from 'react'
import {
  SafeAreaView,
  ScrollView,
  StyleSheet,
  View,
  ImageBackground,
  Animated,
  useWindowDimensions,
  Alert,
  Pressable,
} from 'react-native'
import { useDispatch, useSelector } from 'react-redux'
import { useTranslation } from 'react-i18next'
import i18next from 'i18next'

import * as slidersAction from '../../store/actions/sliders'
import Loading from './Loading'

const Carousel = (props) => {
  const scrollX = useRef(new Animated.Value(0)).current
  const lang = i18next.language

  const { width: windowWidth } = useWindowDimensions()
  const { t, i18n } = useTranslation()
  const [error, setError] = useState()
  const [isLoading, setisLoading] = useState(false)
  const dispatch = useDispatch()
  const images = useSelector((state) => state.sliders.availableSliders)

  const loadSliders = useCallback(async () => {
    setisLoading(true)
    setError(null)

    try {
      await dispatch(slidersAction.fetchSliders(t('sliders.errorMessageFetch')))
    } catch (err) {
      setError(err)
    }
    setisLoading(false)
  })

  useEffect(() => {
    loadSliders()
  }, [])

  if (error) {
    Alert.alert(t('sliders.errorTitle'), t('sliders.errorMessageFetch'), [{ text: 'Ок' }])
    setError(null)
  }

  if (isLoading) {
    return <Loading />
  }

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.scrollContainer}>
        <ScrollView
          horizontal={true}
          style={styles.scrollViewStyle}
          pagingEnabled
          showsHorizontalScrollIndicator={false}
          onScroll={Animated.event(
            [
              {
                nativeEvent: {
                  contentOffset: {
                    x: scrollX,
                  },
                },
              },
            ],
            { useNativeDriver: false }
          )}
          scrollEventThrottle={1}
        >
          {images.map((image, imageIndex) => {
            return (
              <Pressable
                key={imageIndex}
                onPress={() =>
                  +image.enableLink
                    ? props.navigation.navigate('Home', {
                        categoryId: image.categoryId,
                        categoryTitle: image.title,
                        categoryTitleKg: image.titleKg,
                        lang: lang,
                      })
                    : {}
                }
              >
                <View style={{ width: windowWidth, height: 100, maxHeight: 160 }}>
                  <ImageBackground
                    source={{ uri: image.imageUrl }}
                    style={styles.card}
                    resizeMode='contain'
                  />
                </View>
              </Pressable>
            )
          })}
        </ScrollView>
        <View style={styles.indicatorContainer}>
          {images.map((image, imageIndex) => {
            const width = scrollX.interpolate({
              inputRange: [
                windowWidth * (imageIndex - 1),
                windowWidth * imageIndex,
                windowWidth * (imageIndex + 1),
              ],
              outputRange: [8, 16, 8],
              extrapolate: 'clamp',
            })
            return <Animated.View key={imageIndex} style={[styles.normalDot, { width }]} />
          })}
        </View>
      </View>
    </SafeAreaView>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  scrollContainer: {
    alignItems: 'center',
    justifyContent: 'center',
  },
  card: {
    flex: 1,
    overflow: 'hidden',
    alignItems: 'center',
    justifyContent: 'center',
  },
  normalDot: {
    height: 8,
    width: 8,
    borderRadius: 4,
    backgroundColor: 'silver',
    marginHorizontal: 4,
  },
  indicatorContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    marginTop: 2,
    marginBottom: 1,
  },
})

export default Carousel
  • 2
    Can you share a Codesandbox version of this? It's easier to debug for someone who wants to help – Nagaraj Tantri Feb 12 '21 at 09:21
  • please share [MWE](https://en.wikipedia.org/wiki/Minimal_working_example#:~:text=In%20computing%2C%20a%20minimal%20working,to%20be%20demonstrated%20and%20reproduced.&text=A%20minimal%20working%20example%20may,short%20self-contained%20correct%20example.). – Chandan Feb 19 '21 at 05:17

1 Answers1

0

While the code you provided isn't enough to make a working example for testing this, you should be able to do this using ScrollView's scrollTo component method.

To autoscroll, you can call setTimeout inside your loadSliders function:

const loadSliders = useCallback(async () => {
  setisLoading(true)
  setError(null)

  try {
    await dispatch(slidersAction.fetchSliders(t('sliders.errorMessageFetch')))
  } catch (err) {
    setError(err)
  }
  setisLoading(false)
  
  // new code
  let stopAutoScroll = null // consider making this a state variable
  const autoScrollOneStep = () => {
    YOUR_SCROLLVIEW_REF_HERE.scrollTo({ x: YOUR_CURRENT_PAGE_X + X_OFFSET, animated: true })
    stopAutoScroll = setTimeout(autoScrollOneStep, 2000)
  }
  stopAutoScroll = setTimeout(autoScrollOneStep, 2000)
})

You can stop the autoscroll at anytime (possibly in your onScroll method so the autoscrolling stops once the user scrolls) with clearTimeout(stopAutoScroll)

getfugu
  • 140
  • 1
  • 5
  • thank you so much, but I didnt get it clear, Im new in react native, can you please provide me some more information please? thank you again! – ArturShvaiberov Mar 15 '21 at 20:28