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.63k stars 300 forks source link

How to add both left and right margin? #539

Open ivankdev opened 5 months ago

ivankdev commented 5 months ago

This is my basic code example to reproduce situation

 export const CarouselExample = () => {
  const PAGE_WIDTH = SCREEN_WIDTH * 0.8
  const PAGE_HEIGHT = SCREEN_WIDTH / 2

  return (
    <Carousel
      loop={false}
      pagingEnabled
      width={PAGE_WIDTH}
      height={PAGE_HEIGHT}
      style={{ width: '100%' }}
      data={['red', 'green', 'red', 'green', 'red']}
      renderItem={({ item }) => (
        <View
          style={{
            marginLeft: 16,
            width: PAGE_WIDTH,
            height: PAGE_HEIGHT,
            backgroundColor: item,
          }}
        ></View>
      )}
    />
  )
}

Which gives me only this result and only left aligment

first slide (marginLeft=16) -> any center slide -> last slide (marginRight=?) Screenshot 2024-01-26 at 16 05 51 Screenshot 2024-01-26 at 16 05 56 Screenshot 2024-01-26 at 16 06 03

According to design I need carousel component which works this way:

first slide (marginLeft=16) -> any center slide -> last slide (marginRight=16) Screenshot 2024-01-26 at 16 05 51 Screenshot 2024-01-26 at 16 05 56 Screenshot 2024-01-26 at 16 12 52

I need the last item has the same margin from right side like first item from left side. According to examples I can set up only either left or right alignment by marginLeft or marginRight on item component. Moreover your example made by transform: [{ "rotateY": "-180deg" }] which is quite unuseful, changes swipe direction and resets opposite alignment.

So how can I implement that behaviour? Would be happy to get any clue from you guys. Is that possible at all?

PS. for understanding what I'm saying for example on FlatList it could be done by contentInset props

dosubot[bot] commented 5 months ago

🤖

Hey @ivankdev! Great to cross paths with you again. Hope you're doing well!

Based on the information available in the repository, it seems that the react-native-reanimated-carousel component does not directly support custom alignment properties for individual slides. However, you can achieve the desired effect by modifying the renderItem function.

You can add a condition to check if the current item is the first or the last one, and apply different styles accordingly. Here's how you can do it:

export const CarouselExample = () => {
  const PAGE_WIDTH = SCREEN_WIDTH * 0.8
  const PAGE_HEIGHT = SCREEN_WIDTH / 2
  const data = ['red', 'green', 'red', 'green', 'red'];

  return (
    <Carousel
      loop={false}
      pagingEnabled
      width={PAGE_WIDTH}
      height={PAGE_HEIGHT}
      style={{ width: '100%' }}
      data={data}
      renderItem={({ item, index }) => (
        <View
          style={{
            marginLeft: index === 0 ? 16 : 0,
            marginRight: index === data.length - 1 ? 16 : 0,
            width: PAGE_WIDTH,
            height: PAGE_HEIGHT,
            backgroundColor: item,
          }}
        ></View>
      )}
    />
  )
}

In this code, we're checking if the current item (index) is the first one (index === 0) or the last one (index === data.length - 1). If it's the first one, we're applying a 16px left margin, and if it's the last one, we're applying a 16px right margin. For all other items, we're not applying any margin.

This approach should give you the desired effect of having the first slide with a left margin and the last slide with a right margin. However, please note that this is a workaround and might not work perfectly in all scenarios, especially if you have a large number of slides or if the slides have different widths.

I hope this helps! If you have any other questions or need further clarification, feel free to ask.

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

ivankdev commented 5 months ago

The point is that marginRight

marginRight: index === data.length - 1 ? -16 : 0,

doesn't affect component anyhow. And if I set up marginLeft only for first element

marginLeft: index === 0 ? 16 : 0,

I lose common left margin for whole carousel.

So question isn't resolved

https://github.com/dohooo/react-native-reanimated-carousel/assets/37651838/c256dee2-0a94-4171-884c-097a575ade15

ivankdev commented 5 months ago

cc @dohooo maybe you have any clues, thank you!

ahsan-ey-k commented 5 months ago

same question.

ahsan-ey-k commented 5 months ago

I want it to snap from both sides and deactive cards should show from both of the sides.

ivankdev commented 5 months ago

I want it to snap from both sides and deactive cards should show from both of the sides.

I've partially solved it by prop overscrollEnabled={false}, but I needed to play around Carousel style prop

 container: {
   width: SCREEN_WIDTH - CAROUSEL_HORIZONTAL_PADDING - CAROUSEL_CONTENT_SPACING,
   alignSelf: 'flex-start',
   overflow: 'visible', 
 },

Why partially? Because manually by finger it works. But position of last item is still incorrect when autoPlay={true} and loop={false}, when animation happens underthehood

ahsan-ey-k commented 5 months ago

It is not working.

const topPicksCardsCarousal = { width: SCREEN_WIDTH - 50 - 50 alignSelf: 'flex-start', overflow: 'visible',

}

<Carousel overscrollEnabled={false} style={styles.topPicksCardsCarousal} width={Dimen.width * 0.8} height={440} pagingEnabled={true} snapEnabled={true} mode={"horizontal-stack"} loop={true} autoPlay={false} autoPlayReverse={false} data={homeTopPicks} renderItem={renderCard} modeConfig={{ snapDirection: 'left', }} customConfig={() => ({ type: "positive", viewCount: 10 })} />

ivankdev commented 5 months ago

@ahsan-ey-k I mean try to play around with your width, and review your renderItem style of item

manuwebs commented 5 months ago

HI @ivankdev, @ahsan-ey-k not sure if you solved your issue. But from the first example and desired behavior I could replicate the following

https://github.com/dohooo/react-native-reanimated-carousel/assets/22404383/fcae1c66-150f-4847-a999-c985cdc51c39

The only modification I made to the code was basically on PAGE_WIDTH don't know why is just 80% (width * 0.8) but here it should be the amount of space you want to leave on the sides (32 in your case). Then just keep the marginLeft for all items in order to have the same size and spacing.

No issues with autoplay.

Here's the code:

const CarouselExample = () => {
  const PAGE_WIDTH = width - 32;
  const PAGE_HEIGHT = width / 2;

  return (
    <Carousel
      loop={false}
      autoPlay
      pagingEnabled
      width={PAGE_WIDTH}
      height={PAGE_HEIGHT}
      style={{ width: '100%' }}
      data={['red', 'green', 'pink', 'green', 'red']}
      renderItem={({ item }) => (
        <View
          style={{
            marginLeft: 16,
            width: PAGE_WIDTH,
            height: PAGE_HEIGHT,
            backgroundColor: item,
          }}
        />
      )}
    />
  );
};