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

viewPagerAndroid not working after push and back #1317

Open
hezheop opened this issue Jun 2, 2017 · 52 comments
Open

viewPagerAndroid not working after push and back #1317

hezheop opened this issue Jun 2, 2017 · 52 comments

Comments

@hezheop
Copy link

hezheop commented Jun 2, 2017

I use react-native-tab-view , and push to a view ,and back to the last view , the viewPagerAndroid's touch is not working , and the Tab Button clicks without effect
Android:7.0,5.0
react-native : 0.44,
react-native-navigation:1.1.80

@Ehesp
Copy link
Contributor

Ehesp commented Jun 2, 2017

Is the onPress triggering JS side?

@enahum
Copy link

enahum commented Jun 2, 2017

I'm having the same issue, whenever I push a view and then come back no onPress work in any component rendered inside the ViewPagerAndroid, and swiping the pager becomes really really slow

@hezheop
Copy link
Author

hezheop commented Jun 3, 2017

That is the ViewPagerAndroid 's bug I think , and I solve that by using react-native-tab-view ' s TabViewPagerPan https://github.com/react-native-community/react-native-tab-view

@enahum
Copy link

enahum commented Jun 5, 2017

still happens with the suggested library or any other, including https://github.com/leecade/react-native-swiper and the funny thing is that it only happens on Android, IOS works just fine.

If I instead of pop do a resetTo everything works just fine.

@kelvinpompey
Copy link

I am also experiencing this issue.

@enahum
Copy link

enahum commented Jun 7, 2017

So the way I solved it is that on android instead of doing a push and pop I did a show and dismiss modal

@PARAGJYOTI
Copy link

Its a bug in ViewPagerAndroid . In ios its works fine as its based on ScrollView .Any library that implements ViewPagerAndroid ,same problem will occur . Using Modal instead of push will work , but not a good solution.

@dzunglht-ibl
Copy link

this is a critical bug towards android app using viewpager, please help support this ticket guys
Tons of thanks

@t2n3qqq
Copy link

t2n3qqq commented Jun 20, 2017

@dzunglht You can try something like this:

import React, { PureComponent } from 'react';
import {
  View,
  Dimensions,
} from 'react-native';

export default class ViewPagerWrapper extends PureComponent {

  constructor(props) {
    super(props);
    this.props.navigator && 
      this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
  }

  onNavigatorEvent (event) {
    switch(event.id) {
      case 'willAppear':
        this._reattach();
        break;
    }
  }

  state = {
    width: Dimensions.get('window').width,
  }

  render() {
    return (
      <View style={[this.props.style, { flex: 1 }]}>
        <View style={{ width: this.state.width, flex: 1 }}>
          {this.props.children}
        </View>
      </View>
    )
  }

  _x = 0.5

  _reattach = () => {
    this.setState({
      width: this.state.width - this._x,
    }, () => {
      this._x *= -1;
    });
  }

and then use:

<ViewPagerWrapper navigator={this.props.navigator}>
  <YourAwesomeComponent>
    //Component that uses ViewPagerAndroid
    ...
  </YourAwesomeComponent>
</ViewPagerWrapper>

Maybe this is not most elegant solution, but it works for me.

@kelvin-dev
Copy link

@guyca Please have an official fix asap, this is such a critical bug, above way doesn't work.
Thanks

@jykun
Copy link

jykun commented Jun 22, 2017

look at this https://github.com/jykun/react-native-swiper.git, i change viewPageAndroid to scrollView.

@guyca
Copy link
Collaborator

guyca commented Jun 22, 2017

@meow0703 @dzunglht Can you guys upload an example where the bug is reproducible? I doubt this is a bug in RNN, it's probably an issue in the actual component which will require a PR to RN.

@mannol
Copy link

mannol commented Jun 22, 2017

I just came here to confirm that this happens to me too.

@mannol
Copy link

mannol commented Jun 22, 2017

@guyca Steps to reproduce:

  • create root with startTabBasedApp() with x tabs
  • in one tab, render ViewPagerAndroid
  • from that tab push some screen with this.props.navigator.push()
  • press back on the newly pushed screen
  • the ViewPagerAndroid no longer works

@guyca guyca self-assigned this Jun 25, 2017
@dzunglht-ibl
Copy link

Dear folks,
8 days passed, we're looking for your official fix asap
Many thanks

@PARAGJYOTI
Copy link

PARAGJYOTI commented Jul 3, 2017 via email

@kelvin-dev
Copy link

@ALL @guyca Please have a look on below elegant library (built for react-native in mind) and refer how efficiently they use their viewPager, we should extend and/or make use of their effort. Hope that help.
Ref: https://github.com/appintheair/react-native-looped-carousel

@dzunglht-ibl
Copy link

dzunglht-ibl commented Jul 6, 2017

@guyca where are you now, when we have official fix for the ticket ?

@Ehesp
Copy link
Contributor

Ehesp commented Jul 6, 2017

If you guys are waiting on this internally or something then I'd try and look at alternative options for now, there is no timeline on when this will be fixed.

@guyca
Copy link
Collaborator

guyca commented Jul 12, 2017

Hey guys

I managed to take some time today to look into this issue. I think this is actually a bug in the native ViewPager. It seems to be tracking its layout state when the view is attached. Since the view is already laid out when it's added again to the screen - onLayout isn't called which is where mIsFirstLayout is set to false.
Because the ViewPager can't smooth scroll back to the selected item before onLayout stage is completed (since it doesn't know the item size) - smooth scrolling doesn't work.

We can easily trick the system into measuring and going through the entire layout cycle of the ViewPager (essentially invalidating the view) by changing the dimensions of the ViewPagerAndroid when the visibility of the screen changes.

export default class ViewPagerAndroidScreen extends React.Component {
constructor(props) {
    super(props);
    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
    this.state = {
      visible: true
    }
  }

  onNavigatorEvent(event) {
    if (event.id === 'willAppear') {
      this.setState({
        visible: true
      });
    }
    if (event.id === 'willDisappear') {
      this.setState({
        visible: false
      });
    }
  }

  render() {
    return (
      <ViewPagerAndroid
        style={[styles.viewPager, {flex: this.state.visible ? 1 : 0}]}>
        <View>
          <Text>First page</Text>
        </View>
        <View>
          <Text>Second page</Text>
        </View>
      </ViewPagerAndroid>
    );
  }
}

Perhaps we can introduce a property to navigator.pop which will force the native views the layout

@PARAGJYOTI
Copy link

PARAGJYOTI commented Jul 13, 2017

Thanx @guyca . Finally . What a relief . Can you please please build a library or include in react-native-navigation for Snapped RecyclerView . I haven't found any library for Recyclerview in react-native especially for a horizontal swiper that play-store uses .

@andrerfneves
Copy link

The above solution didn't work for me. I went ahead and used a Modal and it worked flawlessly.

@guyca
Copy link
Collaborator

guyca commented Jul 18, 2017

@andrerfneves Modal is displayed over current screen - so the ViewPager isn't detached from window (which is the root cause of this bug)

@andrerfneves
Copy link

andrerfneves commented Jul 20, 2017

@guyca I'm aware of the reason why Modals work. I'm stating that the solution you provided above didn't work for me, aka re-render/calculating height/width again didn't solve my use cause. Just in case other people go through the trouble of implementing your solution.

@mannol
Copy link

mannol commented Jul 24, 2017

I'm here to confirm that @guyca's solution works. Thanks!

@kelvinpompey
Copy link

I am using https://github.com/archriss/react-native-snap-carousel as an alternative and it is working pretty well.

@mannol
Copy link

mannol commented Jul 24, 2017

@kelvinpompey the reason for using viewPagerAndroid (or any control based on it) is that RefreshControl does not work with paged ScrollView

@kelvin-dev
Copy link

@guyca when we have the official fix in next release ? Newbiews don't have time to search out this ticket
Thanks

@Annihil
Copy link

Annihil commented Feb 28, 2018

I confirm @guyca solution fixes the issue with React-Native-ViewPager on Android.
Although, it makes the animation hangs, on both platforms :/

I'm using this to only use the fix on Android

const flex = Platform.select({ios: {flex: 1}, android: {flex: this.state.visible ? 1 : 0}});
<ViewPager style={{...flex}}/>

@janiokq
Copy link

janiokq commented Mar 1, 2018

image
image

In the push
RelativeLayout.removeView( previous view )
In the pop
RelativeLayout.addview(previous view)

RelativeLayout extends ViewGroup

In the native
ViewPager is removed by ViewGroup and added to

Will there be this bug

@janiokq
Copy link

janiokq commented Mar 1, 2018

You can

image
Function is the
private void pushScreenToVisibleStack(LayoutParams layoutParams,
final Screen nextScreen,
final Screen previousScreen,
@nullable final Promise onPushComplete,
@nullable final Screen.OnDisplayListener onDisplay, final Boolean runanime)

image
Function is the
public void pop(final boolean animated, final double jsPopTimestamp, @nullable final OnScreenPop onScreenPop)

image
Function is the
private void swapScreens(boolean animated, final Screen toRemove, Screen previous, OnScreenPop onScreenPop)

All changes in
com.reactnativenavigation.screens ->ScreenStack.java

The problem will be repaired

But when multiple pages exist, the graphics memory will be high

Because all pages are displayed on the page

Do anyone have a better solution? I'm a JavaScript code farm native code that isn't very well understood.

@janiokq
Copy link

janiokq commented Mar 2, 2018

I found the real reason

In the native

react-native-navigation
The implementation is to add and remove views in a ViewGroup

I saw the implementation of ViewPager
image

mFirstLayout It's this guy
This state is used to record whether the viewpager is the first initialization of the layout

He has such a piece of code
image

When navigation is switched on the page
Viewpager is removed from the view and added
It triggered this event
mFirstLayout = true;

Viewpager can't roll.
You can do this

image
Using this class to use viewpager

There's no problem.

@Annihil
Copy link

Annihil commented Mar 3, 2018

@janiokq How did you use a custom class for your ViewPager, please explain how to do

@gusgoose
Copy link

@janiokq Good work finding the problem - is this a solution that works for you? And if so, please could you explain how we can do the same?

@ashokkumar88
Copy link

ashokkumar88 commented May 1, 2018

@t2n3qqq this solution works for me. But if you have multiple carousel/ViewpagerAndroid in a screen then instead of setOnNavigatorEvent you have to use addOnNavigatorEvent

this.props.navigator.addOnNavigatorEvent(this.onNavigatorEvent.bind(this));

@paulbargaoanu
Copy link

paulbargaoanu commented Jun 13, 2018

In case anyone is still encountering this issue while using react-native-tab-view, I would suggest using PagerScroll instead of PagerAndroid, unless you really need PagerAndroid for some reason. I am developing an app for both iOS and Android and initially chose PagerScroll for iOS and PagerAndroid for Android and encountered this unexpected bug only on Android. After some research I thought I'd just try changing the pager and thus far it seems to work flawlessly. Hope this might help someone!

@stale
Copy link

stale bot commented Jul 28, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you believe the issue is still relevant, please test on the latest version and report back. Thank you for your contributions.

@stale stale bot added the 🏚 stale label Jul 28, 2018
@stale
Copy link

stale bot commented Aug 4, 2018

The issue has been closed for inactivity.

@stale stale bot closed this as completed Aug 4, 2018
React Native Navigation automation moved this from To Do to Done Aug 4, 2018
@guyca guyca reopened this Aug 4, 2018
@stale stale bot removed the 🏚 stale label Aug 4, 2018
@guyca guyca added the Wix label Aug 29, 2018
@stale
Copy link

stale bot commented Oct 14, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you believe the issue is still relevant, please test on the latest version and report back. Thank you for your contributions.

@stale stale bot added the 🏚 stale label Oct 14, 2018
@stale
Copy link

stale bot commented Oct 21, 2018

The issue has been closed for inactivity.

@stale stale bot closed this as completed Oct 21, 2018
@guyca guyca reopened this Oct 21, 2018
@edgarbonillag
Copy link

edgarbonillag commented Jan 12, 2019

Hi everyone,

The library 'react-native-tab-view' uses React Native's ViewPagerAndroid as default pager for Android and this component is not working well.

I've found an easy SOLUTION that made my app run without any problem. I just had to tell the 'react-native-tab-view' to use the PagerScroll (which is the default for iOS and its based on RN's ScrollView) and that's it. To do that, you just import {PagerScroll} from 'react-native-tab-view' pass the following prop to the main TabView component:

<TabView
   ...
   renderPager={(props) => <PagerScroll {...props}/>}
   ...
/>

Also you may want to pass this prop too:

swipeEnabled={false}

this will evade some conflicts for example when you are using side drawers on 'react-native-navigation' because they appear by swiping too.

@rat-moonshine
Copy link

rat-moonshine commented Apr 29, 2020

Hi! Can someone guide me how to pass react-native-navigation screens (Navigation.registerComponent(Screens.ScreenA, () => require('./ScreenA'));) to use with react native tab SceneMap? I'm having having error 'invariant violation: native module can not be null' using in RNNv3. Thanks!

const renderScene = SceneMap({
    first: Screens.ScreenA,
    second: Screens.ScreenB
  });

....

render() {
    return (
      <View>
        <TabView
            navigationState={{ index, routes }}
            renderScene={renderScene}
            onIndexChange={setIndex}
            initialLayout={initialLayout}
          />
     </View>
    );
  }

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

No branches or pull requests