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

Android wrong display when using custom scrollInterpolator, slideInterpolatedStyle (ios is fine) #282

Closed
EJohnF opened this issue Mar 9, 2018 · 12 comments

Comments

@EJohnF
Copy link

EJohnF commented Mar 9, 2018

Is this a bug report or a feature request?

Bug report

Have you read the guidelines regarding bug report?

Yes!

Have you read the documentation in its entirety?

yes, and tip/tricks, and know issues (while it seems that it could be related to its)

Have you made sure that your issue hasn't already been reported/solved?

Checked issues list, didnt' find exactly this one.
may be something similar: #262

but actually I use code from there to customize animation

Is the bug specific to iOS or Android? Or can it be reproduced on both platforms?

only on android

Is the bug reproductible in a production environment (not a debug one)?

yes

Have you been able to reproduce the bug in the provided example?

Reproduce in expo https://snack.expo.io/@ejohnf/android-wrong-display-problem

Environment

Environment:
"react": "16.2.0",
"react-native": "0.53.3",
"react-native-snap-carousel": "https://github.com/archriss/react-native-snap-carousel#1eaf0c0",

Target Platform:
Android API_25

Steps to Reproduce

  1. Make Item object - as a square 309x309
  2. carousel setting:
<Carousel
          ref={(c) => { this.carousel = c; }}
          containerCustomStyle={styles.carousel}
          data={this.props.activities}
          firstItem={this.props.position}
          initialNumToRender={this.props.position + 1}
          renderItem={({ item, index }) => <Card {...item} index={index} />}
          onSnapToItem={changeCurrentDayPosition}
          vertical
          scrollInterpolator={stackScrollInterpolator}
          slideInterpolatedStyle={stackAnimatedStyles}
          itemHeight={309}
          sliderHeight={509}
          itemWidth={309}
          layout="stack"
        />
  1. Implement custom interpolation:
// 2 methods to fix swipe problem on IOS, for more info see: https://github.com/archriss/react-native-snap-carousel/issues/262
// also to make animation
export const stackScrollInterpolator = (index, carouselProps) => {
  const range = [0, -1, -2, -3, -4, -5, -6, -7];
  const inputRange = getInputRangeFromIndexes(range, index, carouselProps);
  const outputRange = range;
  return { inputRange, outputRange };
};

// method to make a nice stack animation
export const stackAnimatedStyles = (index, animatedValue, carouselProps) => {
  const sizeRef = carouselProps.vertical ? carouselProps.itemHeight : carouselProps.itemWidth;
  const translateProp = carouselProps.vertical ? 'translateY' : 'translateX';

  const cardOffset = 12.0;
  const scaleFactor = 1 - (cardOffset / sizeRef);

  const getTranslateFromScale = (ind, scale) => {
    const centerFactor = (1 / scale) * ind;
    const centeredPosition = -Math.round(sizeRef * centerFactor);
    const edgeAlignment = Math.round((sizeRef - (sizeRef * scale)) / 2);
    const offset = Math.round((cardOffset * Math.abs(ind)) / scale);

    return centeredPosition - edgeAlignment - offset;
  };

  return {
    opacity: animatedValue.interpolate({
      inputRange: [-7, -6, -5, -4, -3, -2, -1, 0, 1],
      outputRange: [0, 1, 1, 1, 1, 1, 1, 1, 0],
      extrapolate: 'clamp'
    }),
    transform: [{
      scale: animatedValue.interpolate({
        inputRange: [-7, -6, -5, -4, -3, -2, -1, 0],
        outputRange: [
          /* eslint no-restricted-properties:0 */
          Math.pow(scaleFactor, 6),
          Math.pow(scaleFactor, 6),
          Math.pow(scaleFactor, 5),
          Math.pow(scaleFactor, 4),
          Math.pow(scaleFactor, 3),
          Math.pow(scaleFactor, 2),
          scaleFactor,
          1],
        extrapolate: 'clamp'
      })
    }, {
      [translateProp]: animatedValue.interpolate({
        inputRange: [-7, -6, -5, -4, -3, -2, -1, 0],
        outputRange: [
          getTranslateFromScale(-7, Math.pow(scaleFactor, 6)),
          getTranslateFromScale(-6, Math.pow(scaleFactor, 6)),
          getTranslateFromScale(-5, Math.pow(scaleFactor, 5)),
          getTranslateFromScale(-4, Math.pow(scaleFactor, 4)),
          getTranslateFromScale(-3, Math.pow(scaleFactor, 3)),
          getTranslateFromScale(-2, Math.pow(scaleFactor, 2)),
          getTranslateFromScale(-1, scaleFactor),
          getTranslateFromScale(0, 1)
        ],
        extrapolate: 'clamp'
      })
    }]
  };
};

Expected Behavior

I'm trying to achive that design:

2018-03-09_13-15-02

on IOS is looks perfect:

2018-03-09_13-19-18

(and all other cards looks good, and animation cool)

Actual Behavior

Last item on Android:

2018-03-09_13-21-46

All other items:

2018-03-09_13-22-46

Reproducible Demo

https://snack.expo.io/@ejohnf/android-wrong-display-problem

@EJohnF
Copy link
Author

EJohnF commented Mar 9, 2018

also there are problems with swiping on android - after one gesture several cards channged, then scroll back to the one, which should be actually shown

@bd-arc
Copy link
Contributor

bd-arc commented Mar 12, 2018

Hey @EJohnF,

Thanks for the detailed and illustrated issue! It would really help if you could manage to get the Snack example working on Android.

I might be able to try out your code later this week, but I could give it a look sooner with a working example ;-)

In the meantime, can you confirm that you've read the "Custom interpolations" section of the doc, and particularly the "caveats"?

@EJohnF
Copy link
Author

EJohnF commented Mar 12, 2018

Thank you @bd-arc for your response!

Read it now once again - but this Caveats section not really help - bcs I don't use zIndex style

inverted and useScrollView also tried - helps a bit with second (overscroll) problem

@EJohnF
Copy link
Author

EJohnF commented Mar 12, 2018

@bd-arc fixed snack: https://snack.expo.io/@ejohnf/android-wrong-display-problem

(also update link in issue)

In expo it works a bit better than in screenshot above, since I've added zero opacity for 1 item

@bd-arc
Copy link
Contributor

bd-arc commented Mar 15, 2018

Hey @EJohnF,

I've taken a look at the example. The fact that only the first item is affected and that it happens only on Android reminds me of an issue I had with a previous version of React Native.

If you take a look at these lines, you'll see that the first and last items are centered thanks to some custom padding. A few months ago, this padding was ignored on Android and was throwing off slide's centering. I hope there wasn't a recent regression in React Native...

Could you try to override the value locally and see if it allows you to properly center the last item ?

@bd-arc
Copy link
Contributor

bd-arc commented Mar 15, 2018

Hum... Just created a quick example from scratch: apparently, there is a centering issue with all vertical carousels on Android.

I need to look into it.

@bd-arc bd-arc added the bug label Mar 15, 2018
@EJohnF
Copy link
Author

EJohnF commented Mar 17, 2018

@bd-arc when I've changed these rows to

vertical ? {
                paddingTop: this._getContainerInnerMargin(),
                paddingBottom: 300, //this._getContainerInnerMargin(true)
            } : {

And then last item looks better:

screenshot_1521266084

Thanks!

Now problems that all cards show only 2 cards in the stack (instead of 6 in IOS)

@EJohnF
Copy link
Author

EJohnF commented Mar 27, 2018

I think I've found how to solve displaying problem:

  1. change paddingBottom as above
  2. change props removeClippedSubviews to false

and it looks like https://yadi.sk/i/cB5-fZsO3TnyEw

@bd-arc
Copy link
Contributor

bd-arc commented Mar 27, 2018

@EJohnF Good finding :-)

But a workaround was already mentioned in the doc. I didn't think about telling you because I was assuming that you were already aware of the need to set useScrollView to true in order to avoid rendering bugs.

I would recommend this solution over removeClippedSubviews={false}, since it has the same effect but might still provide a bit of optimization. ⚠️ Bear in mind that either solutions are not suited for large data sets since all items will be rendered upfront.

I still need to look into that bottom padding on Android though...

@EJohnF
Copy link
Author

EJohnF commented Mar 27, 2018

I've tried to use useScrollView: true
And it doesn't help with required stack view (checked once again right now)

And removeClippedSubviews={false} may be will not be a big problem, since in 0.54 added support to loading items in both directions...
Anyways thanks for your time and warning!!

But now get the problem with some overscrolling on Android (while overScrollMode: 'never',)
Within one gesture 1,5-2 items can be scrolled, which leads to some flashing or item missing

@bd-arc
Copy link
Contributor

bd-arc commented Mar 27, 2018

Regarding your Android issue, have you tried on a device with a production build? I can't emphasize what's being said in this note enough :-)

To provide more context, you need to know that despite being one of the most wanted feature, the React Native team have not implement yet a proper equivalent of the iOS snapToAlignment/snapToInterval combo on Android. Therefore, we are left with a bunch of hacks, workarounds and debug mode issues... I've done my best to tackle it, but some core things are either missing or buggy and I have no control at all over it.

Still, ideas and PR are always welcome ;-)

@EJohnF
Copy link
Author

EJohnF commented Nov 21, 2019

FYI: updated to the last version of you library - and now it works fine!! Thanks!
(used a heavily customized fork before)

@EJohnF EJohnF closed this as completed Nov 21, 2019
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

2 participants