dohooo / react-native-reanimated-carousel

🎠 React Native swiper/carousel component, fully implemented using reanimated v2, support to iOS/Android/Web. (Swiper/Carousel)
https://react-native-reanimated-carousel.vercel.app
MIT License
2.81k stars 324 forks source link

🚀 What layout style do you want? #88

Closed dohooo closed 2 years ago

dohooo commented 2 years ago

Writing here!

BTW, looking forward to your PR!~ 🍺

dohooo commented 2 years ago

Stellar work on this library. Wondering if a combination of vertical and horizontal mode is possible.

image

Thank you. It seems that it is not possible at present. More modifications are needed.

IAmNatch commented 2 years ago

Hey @dohooo, I've been looking at your multiple example again, and I've been hitting an issue which I would call "overscrolling".

When the carousel is set to "loop", everything works as expected, however when loop is disabled, you can scroll the last element all the way to "position 1" instead of it being the last item in the carousel.

Current Implementation: Slot 1 Slot 2 Slot 3
LastItem Empty Empty
Ideal Implementation Slot 1 Slot 2 Slot 3
ThirdLastItem SecondLastItem LastItem

I've attached a minimal reproduction in expo here: https://snack.expo.dev/@srobbins/reanimated-carousel-overscroll-example

I think this would be made possible by allowing us to set maxPages on the ScrollViewGesture, where maxPages would be totalItems.length - numberOfItemsOnScreen, however there would still be a slight problem of navigating to the last item.

Curious what you think about this!

Edit: I believe this is the same issue as #240.

IAmNatch commented 2 years ago

@dohooo I have a PR that adds support for this here: https://github.com/dohooo/react-native-reanimated-carousel/pull/295

dohooo commented 1 year ago

@dohooo I have a PR that adds support for this here: #295

Solved in #297.

ijhar-nivoda commented 1 year ago

oie_EZQUySpbhBoB hey @dohooo , how can do style like this ? is it possible without parallax ?

vbylen commented 1 year ago

stacked card animations that look like this would be amazing:

https://www.youtube.com/watch?v=xPbRsca_l7c

SinanAldefai commented 1 year ago

One other request: "Auto Height" for horizontal layouts. I know this might not be possible, as the items are currently all positioned absolutely, but it would be great to be able to size to height of the carousel based on the height of the contents. This was achievable in snap-carousel, but they may have been using a very different strategy.

Has someone already found a way for this? Or is it just not possible?

rbhuzwandar commented 1 year ago

How to use parallax mode, but hide the left nad right item. so the active item will show full width screen ?

estebandiazfront commented 11 months ago
Screenshot 2023-11-09 at 17 22 59

Which layout should I use to achieve something like this?

guircoelho commented 2 months ago

Hi! I managed to dynamically retrieve the height of the carousel items. While it requires a bit more effort, it is possible as shown below:

How It Works: 1) Measure Item Heights: Each item is rendered invisibly off-screen to capture its height using the measure function. 2) Set Initial Height: The maximum height of all items is set as the initial height of the carousel. 3) Update on Scroll: As the carousel scrolls, the height is dynamically updated based on the height of the currently visible item.

const Advertising = () => {
  const items = []; // TODO

  const carouselRef = React.useRef<ICarouselInstance>(null);
  const [activeSlide, setActiveSlide] = useState(0);
  const {width: screenWidth} = useWindowDimensions();
  const [itemHeights, setItemHeights] = useState([]);
  const [carouselHeight, setCarouselHeight] = useState(0);
  const itemRefs = useRef([]);

  useEffect(() => {
    const heights = items.map((item, index) => {
      return new Promise(resolve => {
        itemRefs.current[index]?.measure((x, y, width, height) => {
          resolve(height);
        });
      });
    });

    Promise.all(heights).then(heights => {
      setItemHeights(heights);
      setCarouselHeight(Math.max(...heights)); // Set the initial height to the maximum item height
    });
  }, [items]);

  const handleScrollEnd = (index: number) => {
    setCarouselHeight(itemHeights[index]);
    setActiveSlide(index);
  };

  const renderItem = ({
    item,
    index,
    renderHidden,
  }: {
    item: AdsProps;
    index: number;
    renderHidden: boolean;
  }) => {
    return (
      <View
        key={item.cd_matia}
        style={[
          styles.listItem,
          renderHidden && {opacity: 0, zIndex: -1, position: 'absolute'},
          !renderHidden && {height: itemHeights[index]},
        ]}
        ref={ref => renderHidden && (itemRefs.current[index] = ref)}>
        <TouchableOpacity
          activeOpacity={0.7}
          onPress={() => openNewsDetails(item.ds_matia_link)}>
          <CustomImage url={item.imagem} width={120} height={96} />
        </TouchableOpacity>
        <View style={styles.textContainer}>
          <NewsItemSubject subject={item.ds_matia_assun} />
          <TouchableOpacity onPress={() => openNewsDetails(item.ds_matia_link)}>
            <TextPrimary style={styles.listItemTitle}>
              {item.ds_matia_titulo}
            </TextPrimary>
          </TouchableOpacity>
        </View>
      </View>
    );
  };

  const moveAnimation = useRef(new Animated.Value(0)).current;
  const moveOffset = 90;

  useEffect(() => {
    const toValue = -((moveOffset / items.length) * activeSlide);
    if (!isNaN(toValue)) {
      Animated.timing(moveAnimation, {
        toValue: toValue,
        duration: 1000,
        useNativeDriver: true,
        easing: Easing.out(Easing.cubic),
      }).start();
    }
  }, [moveAnimation, activeSlide]);

  return (
    <View style={styles.container}>
      <View style={styles.rowContainer}>
        {items &&
          items.map((item, index) =>
            renderItem({item, index, renderHidden: true}),
          )}
        {/* {items &&
          items.map((item, index) => (
            <View
              key={`measure-${index}`}
              ref={ref => (itemRefs.current[index] = ref)}
              style={[
                styles.listItem,
                {opacity: 0, zIndex: 2, position: 'absolute'},
              ]}>
              <TouchableOpacity
                activeOpacity={0.7}
                onPress={() => openNewsDetails(item.ds_matia_link)}>
                <CustomImage url={item.imagem} width={120} height={96} />
              </TouchableOpacity>
              <View style={styles.textContainer}>
                <NewsItemSubject subject={item.ds_matia_assun} />
                <TouchableOpacity
                  onPress={() => openNewsDetails(item.ds_matia_link)}>
                  <TextPrimary style={styles.listItemTitle}>
                    {item.ds_matia_titulo}
                  </TextPrimary>
                </TouchableOpacity>
              </View>
            </View>
          ))} */}
        <Carousel
          ref={carouselRef}
          data={items}
          width={screenWidth}
          height={carouselHeight || 50}
          loop={true}
          renderItem={({item, index}) =>
            renderItem({item, index, render: false})
          }
          onScrollEnd={handleScrollEnd}
          pagingEnabled={true}
          style={{width: '100%'}}
        />
      </View>
    </View>
  );