Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple active items in each screen #102

Open
mazing opened this issue Jul 26, 2017 · 46 comments
Open

Multiple active items in each screen #102

mazing opened this issue Jul 26, 2017 · 46 comments

Comments

@mazing
Copy link

mazing commented Jul 26, 2017

Would it be possible to have multiple items at one slide just like Apple Music:

screen shot 2017-07-26 at 11 38 35

Would the right approach be to change data such that all elements are grouped with two elements in each group and then print the two elements side-by-side when rendering each item?

However, Airbnb has the same feature where no items are active, but you can only scroll such that two elements are always visible. Can the same behaviour be achieved with the right size options with react-native-snap-carousel?

screen shot 2017-07-26 at 12 47 39

@bd-arc
Copy link
Contributor

bd-arc commented Jul 26, 2017

Regarding your first question, having multiple acting items at once is possible but would require some heavy refactoring. I don't have time to work on it at the moment, but I'll keep that in mind for future releases.

And yes, as a workaround you can group two elements in one slide to emulate the behavior, if:

  • the special index handling is not a no-go for you
  • you're ok with snapping two slides every time you move.

Otherwise, I confirm that you can easily reproduce the second layout. Here is a quick example, using the FlatList version (for the activeSlideAlignment prop):

react-native-snap-carousel example

const { width: viewportWidth, height: viewportHeight } = Dimensions.get('window');
const SLIDE_WIDTH = Math.round(viewportWidth / 2.6);
const ITEM_HORIZONTAL_MARGIN = 15;
const ITEM_WIDTH = SLIDE_WIDTH + ITEM_HORIZONTAL_MARGIN * 2;
const SLIDER_WIDTH = viewportWidth;

<Carousel
  sliderWidth={SLIDER_WIDTH}
  itemWidth={ITEM_WIDTH}
  activeSlideAlignment={'start'}
  inactiveSlideScale={1}
  inactiveSlideOpacity={1}
/>

@bd-arc bd-arc added the feature label Jul 26, 2017
@mazing
Copy link
Author

mazing commented Jul 26, 2017

Awesome! Thanks! Great library :-D

However, it seems if I have uneven number of items, I can swipe to a non-existing item such that, if I scroll as much as I can to the right, the last item is in the left of the screen and a non-existing item takes up the right part of the screen.

@bd-arc
Copy link
Contributor

bd-arc commented Jul 27, 2017

If you're talking about your first idea (2 slides in one), that's to be expected since your itemWidth value is twice the real item's width.

Don't forget that you're "hacking" the plugin ;-)

@devken-net
Copy link

devken-net commented Oct 20, 2017

is there any known reason why on my app all items are look active even I set inactiveSlide values?
Like this

    <Carousel
            data={this.props.items.toArray()}
            renderItem={this.renderItem}
            contentContainerCustomStyle={{  alignItems: 'center' }}
            inactiveSlideScale={0.8}
            inactiveSlideOpacity={0.7}
            sliderWidth={this.state.sliderWidth}
            itemWidth={this.state.itemWidth}
            enableSnap={true}
            loop={true}
            lockScrollWhileSnapping={true}
            autoplay={true}
            autoplayDelay={500}
            autoplayInterval={3000}
            />

@bd-arc
Copy link
Contributor

bd-arc commented Oct 20, 2017

@Markortiz What is your React Native version? If it is not one of the latest, see #173 and particularly this comment.

@devken-net
Copy link

devken-net commented Oct 20, 2017

@bd-arc i'm currently using "react-native": "0.44.0",
base on your explanation. I see the issue now.
But on 3.1.0 infinite loop is not yet supported right?

@bd-arc
Copy link
Contributor

bd-arc commented Oct 22, 2017

Hi @Markortiz,

I didn't realize you've edited your message. Yes, you're right: the loop feature has been released in version 3.3.0.

You have a choice to make:

  • stay with 3.1.0 to get item's animation
  • update to 3.3.0+ to get the loop feature
  • upgrade your RN version to get both.

No easy path here, sorry.

@donnes
Copy link

donnes commented Nov 8, 2017

@bd-arc How I can solve this problem?

However, it seems if I have uneven number of items, I can swipe to a non-existing item such that, if I scroll as much as I can to the right, the last item is in the left of the screen and a non-existing item takes up the right part of the screen.

simulator screen shot - iphone 6 - 2017-11-08 at 16 45 05

@bd-arc
Copy link
Contributor

bd-arc commented Nov 8, 2017

Hi @donnes,

I'm going to need more info to help you with that. Can you please open a new issue and make sure to follow the contributing guidelines?

@donnes
Copy link

donnes commented Nov 8, 2017

Hi @bd-arc
I think is not necessary create a new issue, because the problem is related to this issue.

I create a reproduce Snack to be easy to find the problem, here's the link: https://snack.expo.io/ryxxwAeJG

As @mazing said earlier, following your example (#102 (comment)) it's will generate a blank space at end of the scroll. If you run the exemple above and scroll to right you'll can see a blank space.

I don't know how solve this problem, I tried many things but can't find a solution.

@bd-arc
Copy link
Contributor

bd-arc commented Nov 9, 2017

@donnes I see what you mean. I didn't provide the full example at that time and I now realize that the code from my previous answer can lead to issues like yours.

I've modified the Snack you provided to make it work as expected: https://snack.expo.io/Hynr0n-1z

They were two problems:

  • sliderItemHorizontalMargin needed to be added as paddingHorizontal instead of marginHorizontal since the latter would modify item's length and completely mess with the plugin (this explains the fact that the view was scrolling a bit more to the right each snap, and ended up with a large "blank" section).
  • an outer (yellow) and inner (purple) containers were needed in order for the margin to be properly applied.

Note that plugin's official example implements those two suggestions.

I'll update the relevant doc section to the following:

const horizontalMargin = 20;
const slideWidth = 280;

const sliderWidth = Dimensions.get('window').width;
const itemWidth = slideWidth + horizontalMargin * 2;
const itemHeight = 200;

const styles = Stylesheet.create({
    slide: {
        width: itemWidth,
        height: itemHeight,
        paddingHorizontal: horizontalMargin
        // other styles for your item's container
    },
    slideInnerContainer: {
        width: slideWidth,
        flex: 1
        // other styles for the visible container
    }
};

Do you think it will make things clear enough?

@donnes
Copy link

donnes commented Nov 12, 2017

@bd-arc I believe I did not explain the issue I was passing correctly.

Below is an example of the Carousel on the Airbnb app

airbnb-example

And now the example I sent earlier (https://snack.expo.io/BJ4_VmS1M)

snap-carousel-example

Looking at the examples that I sent you can notice that in the second gif, when the scroll comes to the end, there is a red space as if there was a "ghost" Card.

I believe that the correct behavior is when the scroll reaches the end, the scroll does not exceed the last Card. Some like this:

untitled

@bd-arc
Copy link
Contributor

bd-arc commented Nov 13, 2017

@donnes Ah, I now see what you mean!

To be honest, this can prove tough to implement because it would require modifying ScrollView's width and a bunch of the associated logic when activeSlideAlignment is set to either start or end.

But I'll make sure to take a look at it, as I agree that this would be better from a user experience point of view ;-)

@donnes
Copy link

donnes commented Nov 13, 2017

@bd-arc I'll create a fork and try take a look about it. Thank you for the good job! :D

@bd-arc
Copy link
Contributor

bd-arc commented Nov 13, 2017

@donnes I've just played with the source code to see what I would be able to do about it, but I unfortunately don't think that it can be implemented at the moment.

Currently, we determine the active item when its position meets an imaginary line linked to the value of activeSlideAlignment. For example, with a start value this line is at itemWidth / 2. If we're not able to scroll to this position, the last items will never be seen as active, impairing the entire plugin logic.

The VirtualizedList component provides a scrollToIndex() method that accepts two interesting options: viewPosition and viewOffset. I've previously tried using those as they were supposed to allow the kind of behavior you're after. Unfortunately, they have major drawbacks:

  • viewPosition is buggy as hell
  • viewOffset doesn't work on Android
  • scrollToIndex() is a no-go for now (see this React Native issue).

If you have any idea about how to implement it, I'll be glad to hear your thoughts. Because it seems that I'm kind of stuck until Facebook improves the underlying components (by the way, you can vote to let their team know about it ;-)).

@donnes
Copy link

donnes commented Nov 13, 2017

@bd-arc I had previously tried implemented myself carousel component using FlatList and I got these problems too. Aparently the only way is use ScrollView (for IOs) and ViewPagerAndroid (for Android) but yet I got some problems with the latest versions of React Native (0.50+).

By the way, I'll stud the repo code and try some solutions and I back if find something. And also, I'm going to vote for these features as you are suggested.

Again, thank you for the good job! 👍

@bd-arc
Copy link
Contributor

bd-arc commented Nov 13, 2017

@donnes While the plugin is based on <FlatList />, it is nothing more than a <ScrollView /> in the end ;-)

The ViewPagerAndroid component has been heavily considered since it behaves so much better than the regular ScrollView on Android. Unfortunately, the preview effect (which is the root of the plugin) can't be implemented with it at the moment. A prop peekEnabled has recently been added to it, and our expectations were high, but it just doesn't work...

As you can see, I've tried a lot of things to improve the plugin, but RN's core always gets in the way. I'll be pretty glad if you manage to find a solution :-)

@phithu
Copy link

phithu commented Jan 15, 2018

You can style Carousel with prop contentContainerCustomStyle
contentContainerCustomStyle={{overflow: 'hidden', width: widthItemSlide * (numberSlide)}}
Everything will be Okay

@univers3
Copy link

Yeah, it's a huge miss in my opinion too.
Amazing module but in this situation (multi elements) the space totally kills the user interface.

@bd-arc
Copy link
Contributor

bd-arc commented Feb 26, 2018

@univers3 I heartily agree with you and I'd really like to be able to implement it this way.

But if you've read this comment, you already know that this is no piece of cake and that the horde of React Native bugs add another layer of complexity...

@FoxInFlame
Copy link

FoxInFlame commented Apr 29, 2019

@phithu Amazing! Although it's not an implementation in the module but instead just limiting the width, it works perfectly in my case.

For reference, this is what I did:

<Carousel
    data={this.props.data}
    renderItem={this._renderItem}
    itemWidth={100}
    activeSlideAlignment={'start'}
    {/** Other props here... */}
    contentContainerCustomStyle={{
        overflow: 'hidden',
        width: 100 * this.props.data.length
    }}
/>

@bd-arc bd-arc mentioned this issue Jun 27, 2019
5 tasks
@CyxouD
Copy link

CyxouD commented Oct 17, 2019

thank you @FoxInFlame @phithu! Wanted to note that on Android 9 devices when only SINGLE item Carousel is broken by setting width in contentContainerCustomStyle leading to empty Carousel. So I don't set width in this case

const NUMBER_WHICH_CAUSES_BUG_ON_ANDROID_9 = 1;
contentContainerCustomStyle={{
            overflow: 'hidden',
            width:
            // workaround for case when 1 item 
              connectedItems.length === NUMBER_WHICH_CAUSES_BUG_ON_ANDROID_9
                ? undefined
                : this.itemWidth * connectedItems.length,
          }}

@t-vc
Copy link

t-vc commented Nov 1, 2019

@bd-arc How I can solve this problem?

However, it seems if I have uneven number of items, I can swipe to a non-existing item such that, if I scroll as much as I can to the right, the last item is in the left of the screen and a non-existing item takes up the right part of the screen.

simulator screen shot - iphone 6 - 2017-11-08 at 16 45 05

I'm just using snap-carousel recently and come across this issue as well for the 'right empty space'. I got the solution but require to add some additional code in Carousel.js
First we need to add an additional prop lastItemOffsetWidth: PropTypes.number to know the remaining width on the right we want e.g. margin 10 or 20.

lastly, in function:

_initPositionsAndInterpolators (props = this.props) {
        const { data, itemWidth, itemHeight, scrollInterpolator, vertical, activeSlideAlignment, loop, sliderWidth, lastItemOffsetWidth } = props;
       ...
        this._getCustomData(props).forEach((itemData, index) => {
            ...
			if(this._getCustomData(props).length-1 == index && activeSlideAlignment=='start' && !loop){
				var offset=lastItemOffsetWidth;
				if(offset==undefined) offset=0;
				this._positions[index] = {
					start: index * sizeRef - (sliderWidth - (sizeRef + offset)),
					end: index * sizeRef - (sliderWidth - (sizeRef + offset)) + sizeRef
				};
			}else{
				this._positions[index] = {
					start: index * sizeRef,
					end: index * sizeRef + sizeRef
				};
			}
...

should do the trick.

@bd-arc
Copy link
Contributor

bd-arc commented Nov 4, 2019

Hi @t-vc,

Thanks for sharing your idea!

Will it work with all values of activeSlideAlignment (start, center, end)? If yes, do you mind creating a PR for that and share a quick video of your code in action?

@kristoff2016
Copy link

Do you have any update on this? I was looking for a solution also

@t-vc
Copy link

t-vc commented Nov 24, 2019

Hi, sorry i didn't realise a reply until @kristoff2016 recent comment.
@bd-arc I focus only for activeSlideAlignment start to avoid crashing the others.
I will share it to you guys after 3rd December as currently I can't access my files until date.

@kristoff2016
Copy link

kristoff2016 commented Nov 24, 2019

@t-vc I hope you can share the solution how can you remove the right white space. thanks in advance :)

@t-vc
Copy link

t-vc commented Nov 24, 2019

if(this._getCustomData(props).length-1 == index && activeSlideAlignment=='start' && !loop){
	var offset=lastItemOffsetWidth;
	if(offset==undefined) offset=0;
	this._positions[index] = {
		start: index * sizeRef - (sliderWidth - (sizeRef + offset)),
		end: index * sizeRef - (sliderWidth - (sizeRef + offset)) + sizeRef
	};
}else{
	this._positions[index] = {
		start: index * sizeRef,
		end: index * sizeRef + sizeRef
	};
}

if u notice the original code, this._position[index] is actually calculating each item (start from first to last) snap point, i just add an IF statement to change the last item's snap point, that's all.

@kristoff2016
Copy link

thanks for sharing which file change that I should change or do it? or go to change in the original file in this library? could you help advice me? thank you in advance

@t-vc
Copy link

t-vc commented Nov 24, 2019

just modify the original file Carousel.js

@kristoff2016
Copy link

Yes, it is working well now. sorry for one more question should I move this lib to my original project? if I have ever do run npm install again? thanks in advance

@t-vc
Copy link

t-vc commented Nov 24, 2019

I'm afraid u will have to do so until the author adopt this solution into his latest update.

@kristoff2016
Copy link

Have you raised this PR to the Author? I think it would be great if you could help the Author for this issue that there are many users using yours as well I think.

@t-vc
Copy link

t-vc commented Nov 24, 2019

Actually I'm not familiar with github. I just registered to share my solution. If u can do it then it would be great.

@kristoff2016
Copy link

Okay, I will do it!

@t-vc
Copy link

t-vc commented Nov 24, 2019

Thanks a lot, although it is still some touch up to do to make it perfect but I'm sure the author can make it better.

@kristoff2016
Copy link

Waiting the author review the code and approval

@bd-arc
Copy link
Contributor

bd-arc commented Dec 4, 2019

Thanks @kristoff2016!

Now we just need to get some people to test it and make sure it doesn't break anything. I've gotten cautious after merging some PR that had a lot of negative side effects for some users...

@kristoff2016
Copy link

kristoff2016 commented Dec 4, 2019

Hello, @bd-arc I would say that there is no effect in this PR I tested them all in IOS and Android version in a real device. But Yes, sure we might need some people to test it and make sure that won't affect anything, anyway, thank you very much for very nice plugin.

@HiraNasir
Copy link

HiraNasir commented May 14, 2020

can someone send me link https://github.com/archriss/react-native-snap-carousel/tree/flatlist i can't access it @bd-arc

@hejun041
Copy link

hi guys ,I have some problems
Android:
gif
and in iOS its perfect
Sep-27-2020 15-11-07

@hejun041
Copy link

hejun041 commented Sep 27, 2020

hi guys ,I have some problems
Android:
gif
and in iOS its perfect
2020年9月27日15-11-07

and it cant loop

@hejun041
Copy link

hejun041 commented Sep 27, 2020

hi guys ,I have some problems
Android:
gif
and in iOS its perfect
2020年9月27日15-11-07

This is the code
1.https://github.com/hejun041/react-native-snap-carousel/blob/6f199d37be8d9c959830e8619e6ac84e72e18c59/src/utils/animations.js#L37-L43
2.https://github.com/hejun041/react-native-snap-carousel/blob/6f199d37be8d9c959830e8619e6ac84e72e18c59/src/carousel/Carousel.js#L536-L537
3.https://github.com/hejun041/react-native-snap-carousel/blob/6f199d37be8d9c959830e8619e6ac84e72e18c59/src/carousel/Carousel.js#L616-L622

and And then use it like this

    return <Carousel
      data={data}
      renderItem={this._renderItem.bind(this)}
      sliderWidth={deviceWidth}
      sliderHeight={pxToDp(296)}
      itemWidth={width1}
      inactiveSlideScale={0.842}
      loop hasParallaxImages has2Item
      inactiveSlideOpacity={1}
      activeAnimationType={'decay'}
      activeSlideAlignment={'custom'}
      customMargin={width1}
      slideStyle={styles.imageContainer}
      lockScrollWhileSnapping removeClippedSubviews
    />
      <TouchableOpacity activeOpacity={0.8} key={index}>
        <ParallaxImage
          source={{ uri: 'https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1906469856,4113625838&fm=26&gp=0.jpg' }} showSpinner={false}
          containerStyle={styles.imageContainer}
          style={styles.image}
          parallaxFactor={0}
          dimensions={{ width: pxToDp(177), height: pxToDp(256) }}
          {...parallaxProps}
        />
      </TouchableOpacity>

@hejun041
Copy link

hi guys ,I have some problems
Android:
gif
and in iOS its perfect
Sep-27-2020 15-11-07

I have solved this problem
https://github.com/archriss/react-native-snap-carousel/compare/master...hejun041:master

@fCorleone
Copy link

Hello, @bd-arc I would say that there is no effect in this PR I tested them all in IOS and Android version in a real device. But Yes, sure we might need some people to test it and make sure that won't affect anything, anyway, thank you very much for very nice plugin.

Hi, when will this PR be merged into the code? I think it's really useful to solve this problem.

@dohooo

This comment was marked as spam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests