react-native-reanimated-carousel icon indicating copy to clipboard operation
react-native-reanimated-carousel copied to clipboard

Screen rotation issue

Open Danielcomes92 opened this issue 2 years ago • 8 comments

Hi!, Firstly, thank you for the library, it works very smoothly and has a great performance.

The only thing right now is this, I'm working on a tablet with screen rotation and when I rotate it the carousel item should be centered but it isn't, it's like the width wasn't been calculated again and therefore the slide position is wrong.

Could someone give me some tips or advice? I tried with the bare example and it is happening as well.

Simulator Screen Shot - iPad mini (6th generation) - 2022-12-27 at 10 44 49

Simulator Screen Shot - iPad mini (6th generation) - 2022-12-27 at 10 44 55

Thank you!

Danielcomes92 avatar Dec 27 '22 15:12 Danielcomes92


🔴

👨‍💻 I'm so busy recently, so I'm going away for a little while, but I'll come back by the end of this month.

♥️ Rest assured, I love this project, I will not give up.

2022.11.xx


github-actions[bot] avatar Dec 27 '22 15:12 github-actions[bot]

Hi, You can put width to the "key" prop. The carousel will be re-generated when the width props change. I think this approach could work as a temporary workaround.

dohooo avatar Dec 27 '22 22:12 dohooo

Hi, thanks for getting back to me so quickly.

I'll show you how I did it because I think there's some memory there. The width variable is passed expecting a re-render in the carousel and therefore centering the item, but it doesn't work. Here's my code;

const TabletCarousel = ({ ENTRIES }: TabletCarouselProps) => {
  const { width, height } = useWindowDimensions();

  const [activeSliderIndex, setActiveSliderIndex] = useState(0);

  return (
    <Carousel
      loop={false}
      width={width}
      height={height * 0.75}
      data={ENTRIES}
      style={{ flex: 1 }}
      renderItem={({ index }) => (
        <View
          style={{
            backgroundColor: 'blue',
            flex: 1,
          }}
        >
          <Text
            style={{
              textAlign: 'center',
              fontSize: 30,
            }}
          >
            {index}
          </Text>
        </View>
      )}
      onSnapToItem={(index) => setActiveSliderIndex(index)}
    />
  );
};

Once again, thank you and I'm looking forward to hearing from you.

Danielcomes92 avatar Dec 28 '22 12:12 Danielcomes92

Wondering about this same issue myself. Any progress on this? Especially for elements that take up the entire height and width of the screen; which imo should be a common use case.

@Danielcomes92 did you ever solve this issue?

bruteforks avatar Mar 23 '23 21:03 bruteforks

Here's what I came up with. haven't really done any testing, but it works kinda. Only bug I see is screen flashes old layout for a second when rotating screen. Will update if I make further improvements

import React, {useState, useEffect} from 'react';
import {View, Dimensions, Text} from 'react-native';
import Carousel from 'react-native-reanimated-carousel';

function ResponsiveCarousel() {
  const [screenDimensions, setScreenDimensions] = useState(
    Dimensions.get('window'),
  );

  useEffect(() => {
    const handleDimensionChange = newDimensions => {
      setScreenDimensions(newDimensions.window);
    };

    Dimensions.addEventListener('change', handleDimensionChange);
    return () => {
      Dimensions.removeEventListener('change', handleDimensionChange);
    };
  }, []);

  const data = [
    {
      id: 1,
      text: 'Item 1',
    },
    {
      id: 2,
      text: 'Item 2',
    },
    // ...
  ];

  return (
    <View style={{flex: 1}}>
      <Carousel
        loop
        width={screenDimensions.width}
        height={screenDimensions.height}
        data={data}
        scrollAnimationDuration={1000}
        onSnapToItem={index => console.log('current index:', index)}
        renderItem={({index}) => (
          <View
            style={{
              flex: 1,
              borderWidth: 1,
              justifyContent: 'center',
            }}>
            <Text style={{textAlign: 'center', fontSize: 30}}>
              {data[index].text}
            </Text>
          </View>
        )}
      />
    </View>
  );
}

export default ResponsiveCarousel;

bruteforks avatar Mar 24 '23 00:03 bruteforks

this fixes the layout bug on rotation. Although I'm kinda new to react, so not sure if this is badly implemented or not. The carouselKey does a calculation on rotation and re-renders the carousel.

import React, {useState, useEffect} from 'react';
import {View, Dimensions, Text, ImageBackground, StatusBar} from 'react-native';
import Carousel from 'react-native-reanimated-carousel';

const carousel_0 = require('../assets/carousel_0.jpg');
const carousel_1 = require('../assets/carousel_1.jpg');
const carousel_2 = require('../assets/carousel_2.jpg');

function ResponsiveCarousel() {
  const [screenDimensions, setScreenDimensions] = useState(
    Dimensions.get('window'),
  );

  useEffect(() => {
    const handleDimensionChange = ({window: newDimensions}) => {
      setScreenDimensions(newDimensions);
    };

    Dimensions.addEventListener('change', handleDimensionChange);
    return () => {
      Dimensions.removeEventListener('change', handleDimensionChange);
    };
  }, []);

  const data = [
    {
      id: 1,
      text: 'Item 1',
      image: carousel_0,
    },
    {
      id: 2,
      text: 'Item 2',
      image: carousel_1,
    },
    {
      id: 3,
      text: 'Item 3',
      image: carousel_2,
    },
  ];

  const carouselKey = `${screenDimensions.width}-${screenDimensions.height}`;

  return (
    <View style={{flex: 1}}>
      <StatusBar hidden />
      <Carousel
        key={carouselKey}
        loop
        width={screenDimensions.width}
        height={screenDimensions.height}
        data={data.map(item => item.id)}
        scrollAnimationDuration={1000}
        onSnapToItem={index => console.log('current index:', index)}
        renderItem={({index}) => (
          <ImageBackground
            source={data[index].image}
            resizeMode="cover"
            style={{
              flex: 1,
              justifyContent: 'center',
            }}>
            <Text style={{textAlign: 'center', fontSize: 30, color: 'white'}}>
              {data[index].text}
            </Text>
          </ImageBackground>
        )}
      />
    </View>
  );
}

export default ResponsiveCarousel;

bruteforks avatar Mar 24 '23 16:03 bruteforks

Hi, I have the same issue here. Adding width to the key prop works kinda buggy. Is there any chance to have this problem fixed?

KaterynaPotrusRedge avatar Jan 10 '24 12:01 KaterynaPotrusRedge

I was able to get the carousel to rerender and scroll to the active index with a mixture of useRef, useEffect, and key. Here's a very minimal code snippet:

const SomeCarousel = () => {
  const { width, height } = useWindowDimensions();
  const carouselRef = useRef(null);
  const activeSlideIndex = useRef(0);

  useEffect(() => {
    carouselRef.current?.scrollTo({
      index: activeSlideIndex.current,
      animated: false,
    })
  }, [width])

  return (
    <Carousel
      key={width}
      ref={carouselRef}
      onSnapToItem={(index) => { activeSlideIndex.current = index }}
     // ...all your other props
    />
  );
};

alany411 avatar Feb 15 '24 15:02 alany411