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.85k stars 329 forks source link

The card in the back shows in front of the front card. #671

Open sohuichoi opened 2 months ago

sohuichoi commented 2 months ago

Describe the bug [00:00] The card length is 5. It shows well according to the order. [00:07] The card length is 4. The card in the back shows when it's not its order. it mask the front card. This occurs when the card's length is less than 5.

To Reproduce Steps to reproduce the behavior: this is the code.

import { HomeworkDocument } from '@/submodule/types/homework';
import { ObtainLogDocument } from '@/submodule/types/obtainLog';
import React, { useRef } from 'react';
import { Dimensions, Text, View } from 'react-native';
import Carousel from 'react-native-reanimated-carousel';
import SwipeCard from './SwipeCard';

interface CustomCarouselProps {
    visibleCardIndices: number[];
    homeworks: HomeworkDocument[];
    obtainLogs: ObtainLogDocument[];
    learnerId: number;
    academyId: number;
    handleSwipedCarousel: (homeworkLength: number, index: number) => void;
}

const CustomCarousel: React.FC<CustomCarouselProps> = ({
    visibleCardIndices,
    // homeworks,
    obtainLogs,
    learnerId,
    academyId,
    handleSwipedCarousel,
}) => {
    const homeworks = [
        {
            id: 1,
            title: 'Homework 1',
            description: 'Description 1',
        },
        {
            id: 2,
            title: 'Homework 2',
            description: 'Description 2',
        },
        {
            id: 3,
            title: 'Homework 3',
            description: 'Description 3',
        },
        // {
        //  id: 4,
        //  title: 'Homework 4',
        //  description: 'Description 4',
        // },
        // {
        //  id: 5,
        //  title: 'Homework 5',
        //  description: 'Description 5',
        // },
    ];
    const screenWidth = Dimensions.get('screen').width;
    const currentIndex = useRef(homeworks.length - 1 - +visibleCardIndices[0]);

    return (
        <Carousel
            style={{
                width: '100%',
                height: 352,
                alignItems: 'flex-end',
                justifyContent: 'center',
            }}
            width={screenWidth - 40}
            height={320}
            windowSize={homeworks.length >= 5 ? 5 : homeworks.length}
            pagingEnabled={true}
            snapEnabled={false}
            mode={'vertical-stack'}
            autoFillData={true}
            loop={true}
            data={homeworks}
            modeConfig={{
                snapDirection: 'right',
                stackInterval: -40,
                scaleInterval: 0.1,
                opacityInterval: 0.01,
                moveSize: screenWidth + 1000,
            }}
            defaultIndex={currentIndex.current}
            customConfig={() => ({ type: 'negative', viewCount: 3 })}
            onProgressChange={(offsetProgress: number, absoluteProgress: number) => {
                const absIndex = Math.floor(absoluteProgress);
                const newIndex = homeworks.length - 1 - absIndex;

                console.log('newIndex', newIndex);
                if (currentIndex.current !== newIndex) {
                    currentIndex.current = newIndex;
                    handleSwipedCarousel(homeworks.length, currentIndex.current);
                }
            }}
            renderItem={({ index, item }) => {
                return (
                    <View style={{ width: '100%', height: '100%', backgroundColor: '#f2cfcf', borderWidth: 1 }}>
                        <Text>{item.title}</Text>
                    </View>
                    // <SwipeCard
                    //  learnerId={learnerId}
                    //  academyId={academyId}
                    //  index={homeworks.length - 1 - index}
                    //  visibleCardIndices={visibleCardIndices}
                    //  homework={homeworks[homeworks.length - 1 - index]}
                    //  homeworks={homeworks}
                    //  obtainLogs={obtainLogs}
                    // />
                );
            }}
        />
    );
};

export default CustomCarousel;

Expected behavior However many length the cards have, I want the card shows according to the order. Screenshots If applicable, add screenshots to help explain your problem.

https://github.com/user-attachments/assets/ccdd0209-74d2-4621-aaa5-a406b6847d87

Versions (please complete the following information): "react": "18.2.0", "react-native": "0.73.4", "react-native-reanimated": "^3.15.1", "react-native-reanimated-carousel": "4.0.0-canary.13", "react-native-gesture-handler": "^2.16.2",

Smartphone (please complete the following information):

Additional context Add any other context about the problem here.

dosubot[bot] commented 2 months ago

To fix the issue where the card in the back shows in front of the front card when the card length is less than 5 in your CustomCarousel component, you need to ensure that the z-index of the cards is managed correctly. This can be done by modifying the renderItem function to set the z-index based on the card's position.

Here's an example of how you can modify the renderItem to handle the z-index:

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import Animated, { useAnimatedStyle } from 'react-native-reanimated';

const CustomCarousel: React.FC<CustomCarouselProps> = ({
  visibleCardIndices,
  obtainLogs,
  learnerId,
  academyId,
  handleSwipedCarousel,
}) => {
  const homeworks = [
    { id: 1, title: 'Homework 1', description: 'Description 1' },
    { id: 2, title: 'Homework 2', description: 'Description 2' },
    { id: 3, title: 'Homework 3', description: 'Description 3' },
    // Uncomment these lines to test with more cards
    // { id: 4, title: 'Homework 4', description: 'Description 4' },
    // { id: 5, title: 'Homework 5', description: 'Description 5' },
  ];
  const screenWidth = Dimensions.get('screen').width;
  const currentIndex = useRef(homeworks.length - 1 - +visibleCardIndices[0]);

  return (
    <Carousel
      style={{
        width: '100%',
        height: 352,
        alignItems: 'flex-end',
        justifyContent: 'center',
      }}
      width={screenWidth - 40}
      height={320}
      windowSize={homeworks.length >= 5 ? 5 : homeworks.length}
      pagingEnabled={true}
      snapEnabled={false}
      mode={'vertical-stack'}
      autoFillData={true}
      loop={true}
      data={homeworks}
      modeConfig={{
        snapDirection: 'right',
        stackInterval: -40,
        scaleInterval: 0.1,
        opacityInterval: 0.01,
        moveSize: screenWidth + 1000,
      }}
      defaultIndex={currentIndex.current}
      customConfig={() => ({ type: 'negative', viewCount: 3 })}
      onProgressChange={(offsetProgress: number, absoluteProgress: number) => {
        const absIndex = Math.floor(absoluteProgress);
        const newIndex = homeworks.length - 1 - absIndex;

        console.log('newIndex', newIndex);
        if (currentIndex.current !== newIndex) {
          currentIndex.current = newIndex;
          handleSwipedCarousel(homeworks.length, currentIndex.current);
        }
      }}
      renderItem={({ index, item }) => {
        const animatedStyle = useAnimatedStyle(() => {
          const zIndex = homeworks.length - index; // Ensure the front card has the highest z-index
          return {
            zIndex,
          };
        });

        return (
          <Animated.View key={index} style={[styles.card, animatedStyle]}>
            <Text>{item.title}</Text>
          </Animated.View>
        );
      }}
    />
  );
};

const styles = StyleSheet.create({
  card: {
    position: 'absolute',
    width: '100%',
    height: '100%',
    backgroundColor: '#f2cfcf',
    borderWidth: 1,
  },
});

export default CustomCarousel;

In this example, the zIndex is set based on the card's position in the array, ensuring that the front card has the highest z-index. This should resolve the issue of the back card showing in front of the front card when the card length is less than 5 [1].

To continue talking to Dosu, mention @dosu.

satvicmovement commented 1 month ago

I had the same issue; scrollAnimationDuration={100} solved the issue