React native landscape mode breaks scroll view

Viewed 251

I have been developing a react native app that contains an onboarding screen. App in portrait mode works fine but in landscape mode, it doesn't work correctly. Scrolling and buttons work as I want in portrait mode. In landscape mode, in the second view button's text became "get started" but it has to be "next" and when scrolling it doesn't scroll properly. I added a gif below the code. How can I fix this? I appreciate any help.

const Onboarding = ({ onDone }: OnboardingProps) => {
  const { width } = useDimensions().window;
  const [completed, setCompleted] = useState<boolean>(false);
  const scroll = useRef<ScrollView>(null);
  
  const x = React.useRef<Animated.Value>(new Animated.Value(0)).current;

  const onPress = useCallback((index: number) => {
    console.log("width: ",width)

    console.log(Math.round(index+1))
    console.log(Math.round((index+1)*width))
    scroll.current.scrollTo({ x: width * (index + 1), animated: true });
  }, []);

  React.useEffect(() => {
    x.addListener(({ value }) => {
      
      //this line should be fixed
      if (Math.round(value / width) === slides.length - 1) {
        setCompleted(true);
      } else {
        setCompleted(false);
      }
    });

    return () => x.removeAllListeners();
  }, []);

  return (
    <Box flex={1} backgroundColor="mainBackground">
      <Box flex={3}>{renderScroll(scroll, width, x)}</Box>

      {renderSubSlider(x, width, completed, onDone, onPress)}
    </Box>
  );
}

export default Onboarding;



const renderScroll = (scroll:React.MutableRefObject<ScrollView>, width:number, x:Animated.Value) => {
  return (
    <Animated.ScrollView
      showsHorizontalScrollIndicator={false}
      ref={scroll}
      pagingEnabled
      decelerationRate={9}
      snapToAlignment="center"
      snapToInterval={width}
      scrollEventThrottle={16}
      onScroll={Animated.event([{ nativeEvent: { contentOffset: { x } } }], {
        useNativeDriver: true,
      })}
      
      horizontal
      bounces={false}
      contentContainerStyle={{ flexGrow: 1}}
    >
      {slides.map((data, index) => {
        const opacity = x.interpolate({
          inputRange: [
            (index - 0.5) * width,
            index * width,
            (index + 0.5) * width,
          ],
          outputRange: [0.5, 1, 0.5],
        });

        return (
          <Slider key={index}>
            <Animated.View style={{ opacity }}>
              <SliderImage src={data.src} />
              <Box paddingHorizontal="l">
                <SliderTitle>{data.label}</SliderTitle>
                <SliderText>{data.description}</SliderText>
              </Box>
            </Animated.View>
          </Slider>
        );
      })}
    </Animated.ScrollView>
  );
};

const renderSubSlider = (x:Animated.Value, width:number, completed:boolean, onDone:() => void, onPress:(index:number) => void) => {
  
  
  return (
    <SubSlider >
      <SubSliderItem>
        {slides.map((_, index) => {
          return (
            <Dot
              key={index + 1}
              currentIndex={Animated.divide(x, width)}
              {...{ index }}
            />
          );
        })}
      </SubSliderItem>
      <SubSliderItem>
        <Button
          onPress={() => {
            if (completed) {
              onDone();
            } else {
              //this line should be fixed
              onPress((x as any)._value / width);
            }
          }}
          backgroundColor="onboardingButtonColor"
          rounded
          size="medium"
        >
          {completed ? "Get Started" : "Next"}
        </Button>
      </SubSliderItem>
    </SubSlider>
  );
};

enter image description here

0 Answers
Related