React-native-tab-view: Android: Nested tab-view doesn't display children

Created on 19 Jan 2017  路  19Comments  路  Source: satya164/react-native-tab-view

On Android, there are some issues with ViewPagerAndroid, when it's nested inside a ScrollView.

This is a description of the issue on a similar component:

https://github.com/skv-headless/react-native-scrollable-tab-view/issues/187

Also, I think this is what the user that opened #24 meant.

If you edit TabViewAnimated.js like this, it works on Android

switch (Platform.OS) {
case 'android':
  // TabViewPager = require('./TabViewPagerAndroid').default;
  // break;
case 'ios':
  TabViewPager = require('./TabViewPagerScroll').default;
  break;
default:
  TabViewPager = require('./TabViewPagerPan').default;
  break;
}

Most helpful comment

If anyone else is having this problem here's my implementation of the workaround suggested by satya164, loosely based on the ScrollViewExample code here.

Thanks for the tip btw, I was really stuck on this!

import { Platform } from 'react-native'
import { TabViewAnimated, TabViewPagerScroll, TabViewPagerPan, TabBar } from 'react-native-tab-view'

/* ... Omitted for brevity ... */

  _renderPager = (props) => {
   return (Platform.OS === 'ios') ? <TabViewPagerScroll {...props} /> : <TabViewPagerPan {...props} />
  }

  render () {
    return (
      <TabViewAnimated style={styles.container}
        navigationState={this.state}
        renderScene={this._renderScene}
        renderHeader={this._renderHeader}
        onRequestChangeTab={this._handleChangeTab}
        renderPager={this._renderPager}
      />
    )
  }
}

All 19 comments

I am not sure if there's anything I can do to fix it. you can use the renderPager prop of TabViewAnimated to use TabViewPagerPan without having to edit the files

I'll check that out

If anyone else is having this problem here's my implementation of the workaround suggested by satya164, loosely based on the ScrollViewExample code here.

Thanks for the tip btw, I was really stuck on this!

import { Platform } from 'react-native'
import { TabViewAnimated, TabViewPagerScroll, TabViewPagerPan, TabBar } from 'react-native-tab-view'

/* ... Omitted for brevity ... */

  _renderPager = (props) => {
   return (Platform.OS === 'ios') ? <TabViewPagerScroll {...props} /> : <TabViewPagerPan {...props} />
  }

  render () {
    return (
      <TabViewAnimated style={styles.container}
        navigationState={this.state}
        renderScene={this._renderScene}
        renderHeader={this._renderHeader}
        onRequestChangeTab={this._handleChangeTab}
        renderPager={this._renderPager}
      />
    )
  }
}

@Polidoro thanks for the snippet. nested Tabview on Android is finally functional. :)

@satya164 Hi! When I use @Polidoro 's example I get the following error:
"The specified child already has a parent. You must call removiewView() on the child's parent first."

Do you have any idea why this erroris thrown?

Can you paste your code? Also what version of react-native-tab-view are you using (since as jasan-s mentioned the behavior changed recently)

@Polidoro thanks for the fast response! this is my class. Basically a copy from the example page.

class Profile extends React.Component {
  state = {
    index: 0,
    routes: [
      { key: '1', title: 'First' },
      { key: '2', title: 'Second' },
      { key: '3', title: 'third' },
    ],
  };

  componentDidMount(){
    Actions.refresh({title: this.props.profile.username});
  }

  _handleChangeTab = (index) => {
    this.setState({ index });
  };

  _renderPager = (props) => {
    return (Platform.OS === 'ios') ? <TabViewPagerScroll {...props} /> : <TabViewPagerPan   {...props} />
  };

  _renderHeader = (props) => {
    return <TabBar {...props} />;
  };

  _renderScene = ({ route }) => {
    switch (route.key) {
      case '1':
        return <ProfileMedia  />;
      case '2':
        return <ProfileFollowers  />;
      case '3':
        return <ProfileWorkoutPlans  />;
      default:
        return null;
    }
  };

  render(){
    return(
      <ScrollView style={styles.mainContainer}>
        <ProfileHeader profile={this.props.profile} />

        <TabViewAnimated navigationState={this.state}
                         renderScene={this._renderScene}
                         renderPager={this._renderPager}
                         renderHeader={this._renderHeader}
                         onRequestChangeTab={this._handleChangeTab}/>

      </ScrollView>
    )
  }
}


export default Profile;

I assume you're on v0.0.61?

Does the error occur on Android too or just iOS? Have you tried swapping the ScrollView out for a regular View to see if that has any impact?

I was on v0.0.62, downgraded to .61 and it works now! Thanks a bunch @Polidoro
I am using android.
I am experiencing another bug now where the entire app freezes and throws Max Call stack exceeded error when switching tabs after a few taps, but will probably create separate issue.

Definitely a bug with React Native since I'm not doing any weird stuff here. And I was able to successfully nest it.

Are you sure? After diving into this today I found that on the second time I change tabs,
_renderPager, _renderHeader, _renderScene and _handleChangeTab() are in a loop, infinitely being called until the max call stack error stops the loop. _handleChangeTab is even called with different index everytime.

When I wait 30 seconds between each click, this does not occur. Also when I don't use TabViewPagerPan on Android it works just fine..

"The specified child already has a parent. You must call removiewView() on the child's parent first." doesn't sound like an infinite loop.

Please open a new issue with the code if there is an infinite loop and I'll look into it.

@satya164 that was the error I got implementing Polidoro's fix with V 0.0.6.2. With V0.0.6.1 the error was gone, but now I have an inf loop. I'll create a new issue, thanks.

Not sure if this helps clarify but I wrote that snippet well before v0.0.62 was released. v0.0.59 (or around there) made that workaround unnecessary.

I'll downgrade again, thnx for the headsup. However even if it fixes it, the inf loop is still worth looking into.

@Polidoro the downgrade fixed it again. V0.0.59 in combination with your implementation above works perfectly!

@satya164 let me know if you want to explore the inf loop with me on V0.0.61. I can create an issue.
The "The specified child already has a parent. You must call removiewView() on the child's parent first." is most likely a React-native issue.

Please create an issue. I'm on vacation right now, but will look as soon as I get time.

i have not tried this yet but I'm about to switch to react-navigation which uses this lib. @Polidoro , how would I conditional render pagers for it, since I don't think you have direct access to the same props ?

Hi @jasan-s! I'm no expert but you might be able to set conditional rendering by using the lazy prop on TabViewAnimated and then adding conditions to the individual scenes.

If you can explain in more detail what you're trying to accomplish maybe I can be more helpful?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

QuentinBrosse picture QuentinBrosse  路  4Comments

jouderianjr picture jouderianjr  路  3Comments

glennvgastel picture glennvgastel  路  3Comments

compojoom picture compojoom  路  4Comments

moerabaya picture moerabaya  路  4Comments