React-native-tab-view: Empty view is rendered when scenes height Differs

Created on 23 May 2017  路  16Comments  路  Source: satya164/react-native-tab-view

Hi all , Facing issue in tab bar,
When Tabview is inside scrollview, getting empty views if height differs in children scenes , I mean Tabs

Most helpful comment

Expo link for the same ,,
https://snack.expo.io/HyHCMrQvZ

All 16 comments

import React, { Component } from 'react';
import {
  Animated,
  Platform,
  StatusBar,
  StyleSheet,
  Text,
  View,
  ScrollView
} from 'react-native';
import { TabViewAnimated, TabBar,TabViewPagerScroll, TabViewPagerPan } from 'react-native-tab-view';
const HEADER_MAX_HEIGHT = 300;
const HEADER_MIN_HEIGHT = Platform.OS === 'ios' ? 0 : 0;
const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT;

export default class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      scrollY: new Animated.Value(0),
      ydis:0,
      index: 0,
    routes: [
      { key: '1', title: 'First' },
       { key: '2', title: 'Second' },
    ],
    };
    this.onScroll=this.onScroll.bind(this);
  }

   _main: Object;

 onScroll(e){
     var yDist=e.nativeEvent.contentOffset.y;
     console.log('====================================');
     console.log(yDist);
     console.log('====================================');
     const direction = (yDist > 0 && yDist > this.state.ydis)
        ? 'down'
        : 'up'
     if(direction=='down'){
        if(yDist>=this.state.ydis){
            if(yDist>=0 && yDist<=HEADER_MAX_HEIGHT){
            var yScroll= new Animated.Value(yDist);
            this.setState({scrollY:yScroll});
            }else{
            var yScroll= new Animated.Value(HEADER_MAX_HEIGHT);
            this.setState({scrollY:yScroll});
            }
        }

     }else{
       if(yDist>=40 ){
            var yScroll= new Animated.Value(yDist);
            this.setState({scrollY:yScroll});
            }else{
              var yScroll= new Animated.Value(0);
            this.setState({scrollY:yScroll});
            }
     }   

     this.setState({ydis:yDist});

 }

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

  render() {
    const headerTranslate = this.state.scrollY.interpolate({
      inputRange: [0, HEADER_SCROLL_DISTANCE],
      outputRange: [0, -HEADER_SCROLL_DISTANCE],
      extrapolate: 'clamp',
    });

    const imageOpacity = this.state.scrollY.interpolate({
      inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],
      outputRange: [1, 1, 0],
      extrapolate: 'clamp',
    });
    const imageTranslate = this.state.scrollY.interpolate({
      inputRange: [0, HEADER_SCROLL_DISTANCE],
      outputRange: [0, 100],
      extrapolate: 'clamp',
    });



    return (
      <View style={[styles.fill]}>

       <Animated.ScrollView
          scrollEventThrottle={1}
          style={{}}
           ref={el => (this._main = el)}
          automaticallyAdjustContentInsets={true}
          onScroll={Animated.event(
            [{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
            { useNativeDriver: true },
          )}
        >
          <TabViewAnimated
        style={[styles.container,{marginTop:HEADER_MAX_HEIGHT}]}
        navigationState={this.state}
        renderScene={this._renderScene}
        renderHeader={this._renderHeader}
        onRequestChangeTab={this._handleChangeTab}
        renderPager={this._renderPager}
      />
        </Animated.ScrollView>
        <Animated.View
          style={[
            styles.header,
            { transform: [{ translateY: headerTranslate }] },
          ]}
        >
          <Animated.Image
            style={[
              styles.backgroundImage,
              {
                opacity: imageOpacity,
                transform: [{ translateY: imageTranslate }],
              },
            ]}
             source={{uri: 'https://az616578.vo.msecnd.net/files/responsive/cover/main/desktop/2016/09/12/636092494089079016-677881086_art.jpg'}}
          />
        </Animated.View>
      </View>
    );
  }


  _first: Object;
   _second: Object;

  _handleChangeTab = (index) => {
   this._main._component.scrollTo({ y: 0 });
    this.setState({ index });
  };

  _handleTabItemPress = ({ route }) => {
      if (route !== this.state.routes[this.state.index]) {
        return;
      }
      switch (route.key) {
        case '1':
          if (this._first) {
           this._first.scrollTo({ y: 0 });
           this._main._component.scrollTo({ y: 0 });
          }
          break;
        case '2':
          if (this._second) {
            this._second.scrollTo({ y: 0 });
            this._main._component.scrollTo({ y: 0 });
          }
          break;
      }
    };


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


  _renderScene = ({ route }) => {
    switch (route.key) {
    case '1':
      return(  <ScrollView
         ref={el => (this._first = el)}

       >
        <View style={[ styles.page, { backgroundColor: '#ff4081' } ]} />
        </ScrollView>);
       case '2':
      return(<ScrollView
        ref={el => (this._second = el)}

      >
        <View style= { {backgroundColor: 'teal' , height:20, } } />
        </ScrollView>);
    default:
      return null;
    }
  };
}

const styles = StyleSheet.create({
  fill: {
    flex: 1,
  },
  content: {
    flex: 1,
  },
  container: {
    flex:1,
  },
  page: {
    height:2000,
    alignItems: 'center',
  },
  header: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    backgroundColor: 'transparent',
    overflow: 'hidden',
    height: HEADER_MAX_HEIGHT,
  },
  backgroundImage: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    width: null,
    height: HEADER_MAX_HEIGHT,
    resizeMode: 'cover',
  },
  bar: {
    backgroundColor: 'transparent',
    marginTop: Platform.OS === 'ios' ? 28 : 38,
    height: 32,
    alignItems: 'center',
    justifyContent: 'center',
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
  },
  title: {
    color: 'white',
    fontSize: 18,
  },
  scrollViewContent: {
    marginTop: HEADER_MAX_HEIGHT,
  },
  row: {
    height: 40,
    margin: 16,
    backgroundColor: '#D3D3D3',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Above is the source code

Hi. just add height:1000 in the style.fill or Animated.ScrollView add height

Hi @Juxtlie , no effect , problem persists

solved the isuue,

Find the answer in below comments

Closing since the issue is resolved.

@ashrithks can u share your solution

@ashrithks

XKCD 979
Wisdom of the Ancients

Discussion of the comic:

There's one thing worse: a single followup reading just

Never mind, I figured it out.

This isn't an issue affecting me personally, but if you solve an issue you've requested help from the community on, please do post your solution.

Hi Folks,
Sorry for the late reply...

import React, { Component } from 'react';
import {
Animated,
Platform,
StatusBar,
StyleSheet,
Text,
View,
ScrollView,
Dimensions
} from 'react-native';
import { TabViewAnimated, TabBar, TabViewPagerScroll, TabViewPagerPan } from 'react-native-tab-view';
const HEADER_MAX_HEIGHT = 300;
const HEADER_MIN_HEIGHT = Platform.OS === 'ios' ? 0 : 0;
const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT;

export default class App extends Component {
constructor(props) {
super(props);

    this.state = {
        scrollY: new Animated.Value(0),
        ydis: 0,
        index: 0,
        routes: [
            { key: '1', title: 'First' },
            { key: '2', title: 'Second' },
        ],
        headerHeight: 0,
        tab1Height: 0,
        tab2Height: 0
    };
    this.onScroll = this.onScroll.bind(this);
}

_main: Object;

onScroll(e) {
    var yDist = e.nativeEvent.contentOffset.y;
    console.log('====================================');
    console.log(yDist);
    console.log('====================================');
    const direction = (yDist > 0 && yDist > this.state.ydis)
        ? 'down'
        : 'up'
    if (direction == 'down') {
        if (yDist >= this.state.ydis) {
            if (yDist >= 0 && yDist <= HEADER_MAX_HEIGHT) {
                var yScroll = new Animated.Value(yDist);
                this.setState({ scrollY: yScroll });
            } else {
                var yScroll = new Animated.Value(HEADER_MAX_HEIGHT);
                this.setState({ scrollY: yScroll });
            }
        }

    } else {
        if (yDist >= 40) {
            var yScroll = new Animated.Value(yDist);
            this.setState({ scrollY: yScroll });
        } else {
            var yScroll = new Animated.Value(0);
            this.setState({ scrollY: yScroll });
        }
    }

    this.setState({ ydis: yDist });

}

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

onLayout(e) {
    const { nativeEvent: { layout: { height } } } = e;
    const hed = height + 50;
    this.setState({ headerHeight: hed })
}


render() {
    const headerTranslate = this.state.scrollY.interpolate({
        inputRange: [0, HEADER_SCROLL_DISTANCE],
        outputRange: [0, -HEADER_SCROLL_DISTANCE],
        extrapolate: 'clamp',
    });

    const imageOpacity = this.state.scrollY.interpolate({
        inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],
        outputRange: [1, 1, 0],
        extrapolate: 'clamp',
    });
    const imageTranslate = this.state.scrollY.interpolate({
        inputRange: [0, HEADER_SCROLL_DISTANCE],
        outputRange: [0, 100],
        extrapolate: 'clamp',
    });
    let scrollHeight = 0;
    if (this.state.index === 0) {
        scrollHeight = this.state.headerHeight + 20;
    } else {
        scrollHeight = this.state.headerHeight + 2000;
    }

    return (
        <View style={[styles.fill]}>
            <Animated.View
                style={[
                    styles.header,
                    { transform: [{ translateY: headerTranslate }] },
                ]}
                onLayout={this.onLayout.bind(this)}
            >
                <Animated.Image
                    style={[
                        styles.backgroundImage,
                        {
                            opacity: imageOpacity,
                            transform: [{ translateY: imageTranslate }],
                        },
                    ]}
                    source={{ uri: 'https://az616578.vo.msecnd.net/files/responsive/cover/main/desktop/2016/09/12/636092494089079016-677881086_art.jpg' }}
                />
            </Animated.View>

            <Animated.ScrollView
                scrollEventThrottle={1}
                style={{
                }}
                contentContainerStyle={{ height: scrollHeight }}
                ref={el => (this._main = el)}
                automaticallyAdjustContentInsets={true}
                onScroll={Animated.event(
                    [{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
                    { useNativeDriver: true },
                )}
            >
                <TabViewAnimated
                    style={[styles.container, { marginTop: HEADER_MAX_HEIGHT }]}
                    navigationState={this.state}
                    renderScene={this._renderScene}
                    renderHeader={this._renderHeader}
                    onIndexChange={this._handleChangeTab}
                    renderPager={this._renderPager}
                />
            </Animated.ScrollView>

        </View >
    );
}


_first: Object;
_second: Object;

_handleChangeTab = (index) => {
    this._main._component.scrollTo({ y: 0 });
    this.setState({ index });
};

_handleTabItemPress = ({ route }) => {
    if (route !== this.state.routes[this.state.index]) {
        return;
    }
    switch (route.key) {
        case '1':
            if (this._first) {
                this._first.scrollTo({ y: 0 });
                this._main._component.scrollTo({ y: 0 });
            }
            break;
        case '2':
            if (this._second) {
                this._second.scrollTo({ y: 0 });
                this._main._component.scrollTo({ y: 0 });
            }
            break;
    }
};


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


_renderScene = ({ route }) => {
    switch (route.key) {
        case '1':
            return (<ScrollView
                ref={el => (this._first = el)}

            >
                <View style={[styles.page, { backgroundColor: '#ff4081' }]} />
            </ScrollView>);
        case '2':
            return (<ScrollView
                ref={el => (this._second = el)}

            >
                <View style={{ backgroundColor: 'teal', height: 2000, }} />
            </ScrollView>);
        default:
            return null;
    }
};

}

const styles = StyleSheet.create({
fill: {
flex: 1,
},
content: {
flex: 1,
},
container: {
flex: 1,
},
page: {
height: 20,
alignItems: 'center',
},
header: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
backgroundColor: 'transparent',
overflow: 'hidden',
height: HEADER_MAX_HEIGHT,
},
backgroundImage: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
width: null,
height: HEADER_MAX_HEIGHT,
resizeMode: 'cover',
},
bar: {
backgroundColor: 'transparent',
marginTop: Platform.OS === 'ios' ? 28 : 38,
height: 32,
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
top: 0,
left: 0,
right: 0,
},
title: {
color: 'white',
fontSize: 18,
},
scrollViewContent: {
marginTop: HEADER_MAX_HEIGHT,
},
row: {
height: 40,
margin: 16,
backgroundColor: '#D3D3D3',
alignItems: 'center',
justifyContent: 'center',
},
});

@melihberberolu , @Oblongmana ...
I calculate the height of header and + 50 is tabheader height,,,
then added a prop to scrollview...
contentContainerStyle={{ height: scrollHeight }}
i change the scrollheight based on tabs

if (this.state.index === 0) {
scrollHeight = this.state.headerHeight + 20;
} else {
scrollHeight = this.state.headerHeight + 2000;
}

i hard coded the tab heights,
U can use onlayout Function to get the dynamic height of tabs

@Oblongmana ,
Contributors closed this issue, with out asking the solution.
so ,,i didnt revisit this issue till yesterday when i saw mails regarding this.
Sorry for the late reply

For dynamic tab height example

import React, { Component } from 'react';
import {
Animated,
Platform,
StatusBar,
StyleSheet,
Text,
View,
ScrollView,
Dimensions
} from 'react-native';
import { TabViewAnimated, TabBar, TabViewPagerScroll, TabViewPagerPan } from 'react-native-tab-view';
const HEADER_MAX_HEIGHT = 300;
const HEADER_MIN_HEIGHT = Platform.OS === 'ios' ? 0 : 0;
const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT;
const deviceHeight = Dimensions.get('window').height;
export default class App extends Component {
constructor(props) {
super(props);

    this.state = {
        scrollY: new Animated.Value(0),
        ydis: 0,
        index: 0,
        routes: [
            { key: '1', title: 'First' },
            { key: '2', title: 'Second' },
        ],
        headerHeight: 0,
        tab1Height: 0,
        tab2Height: 0
    };
    this.onScroll = this.onScroll.bind(this);
}

_main: Object;

onScroll(e) {
    var yDist = e.nativeEvent.contentOffset.y;
    console.log('====================================');
    console.log(yDist);
    console.log('====================================');
    const direction = (yDist > 0 && yDist > this.state.ydis)
        ? 'down'
        : 'up'
    if (direction == 'down') {
        if (yDist >= this.state.ydis) {
            if (yDist >= 0 && yDist <= HEADER_MAX_HEIGHT) {
                var yScroll = new Animated.Value(yDist);
                this.setState({ scrollY: yScroll });
            } else {
                var yScroll = new Animated.Value(HEADER_MAX_HEIGHT);
                this.setState({ scrollY: yScroll });
            }
        }

    } else {
        if (yDist >= 40) {
            var yScroll = new Animated.Value(yDist);
            this.setState({ scrollY: yScroll });
        } else {
            var yScroll = new Animated.Value(0);
            this.setState({ scrollY: yScroll });
        }
    }

    this.setState({ ydis: yDist });

}

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

onLayout(e) {
    const { nativeEvent: { layout: { height } } } = e;
    const hed = height + 50;
    this.setState({ headerHeight: hed })
}

onLayoutTab1(e) {
    const { nativeEvent: { layout: { height } } } = e;
    this.setState({ tab1Height: height })
}
onLayoutTab2(e) {
    const { nativeEvent: { layout: { height } } } = e;
    this.setState({ tab2Height: height })
}


render() {
    const headerTranslate = this.state.scrollY.interpolate({
        inputRange: [0, HEADER_SCROLL_DISTANCE],
        outputRange: [0, -HEADER_SCROLL_DISTANCE],
        extrapolate: 'clamp',
    });

    const imageOpacity = this.state.scrollY.interpolate({
        inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],
        outputRange: [1, 1, 0],
        extrapolate: 'clamp',
    });
    const imageTranslate = this.state.scrollY.interpolate({
        inputRange: [0, HEADER_SCROLL_DISTANCE],
        outputRange: [0, 100],
        extrapolate: 'clamp',
    });
    let scrollHeight = deviceHeight;
    if (this.state.index === 0) {
        if (this.state.tab1Height > (deviceHeight - this.state.headerHeight)) {
            scrollHeight = this.state.headerHeight + this.state.tab1Height;
        }
    } else {
        if (this.state.tab2Height > (deviceHeight - this.state.headerHeight)) {
            scrollHeight = this.state.headerHeight + this.state.tab2Height;
        }
    }

    return (
        <View style={[styles.fill]}>
            <Animated.View
                style={[
                    styles.header,
                    { transform: [{ translateY: headerTranslate }] },
                ]}
                onLayout={this.onLayout.bind(this)}
            >
                <Animated.Image
                    style={[
                        styles.backgroundImage,
                        {
                            opacity: imageOpacity,
                            transform: [{ translateY: imageTranslate }],
                        },
                    ]}
                    source={{ uri: 'https://az616578.vo.msecnd.net/files/responsive/cover/main/desktop/2016/09/12/636092494089079016-677881086_art.jpg' }}
                />
            </Animated.View>

            <Animated.ScrollView
                scrollEventThrottle={1}
                style={{
                }}
                contentContainerStyle={{ height: scrollHeight }}
                ref={el => (this._main = el)}
                automaticallyAdjustContentInsets={true}
                onScroll={Animated.event(
                    [{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
                    { useNativeDriver: true },
                )}
            >
                <TabViewAnimated
                    style={[styles.container, { marginTop: HEADER_MAX_HEIGHT }]}
                    navigationState={this.state}
                    renderScene={this._renderScene}
                    renderHeader={this._renderHeader}
                    onIndexChange={this._handleChangeTab}
                    renderPager={this._renderPager}
                />
            </Animated.ScrollView>

        </View >
    );
}


_first: Object;
_second: Object;

_handleChangeTab = (index) => {
    this._main._component.scrollTo({ y: 0 });
    this.setState({ index });
};

_handleTabItemPress = ({ route }) => {
    if (route !== this.state.routes[this.state.index]) {
        return;
    }
    switch (route.key) {
        case '1':
            if (this._first) {
                this._first.scrollTo({ y: 0 });
                this._main._component.scrollTo({ y: 0 });
            }
            break;
        case '2':
            if (this._second) {
                this._second.scrollTo({ y: 0 });
                this._main._component.scrollTo({ y: 0 });
            }
            break;
    }
};


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


_renderScene = ({ route }) => {
    switch (route.key) {
        case '1':
            return (<ScrollView
                ref={el => (this._first = el)}

            >
                <View
                    onLayout={this.onLayoutTab1.bind(this)}
                    style={[styles.page, { backgroundColor: '#ff4081' }]} />
            </ScrollView>);
        case '2':
            return (<ScrollView
                ref={el => (this._second = el)}

            >
                <View
                    onLayout={this.onLayoutTab2.bind(this)}
                    style={{ backgroundColor: 'teal', height: 2000, }} />
            </ScrollView>);
        default:
            return null;
    }
};

}

const styles = StyleSheet.create({
fill: {
flex: 1,
},
content: {
flex: 1,
},
container: {
flex: 1,
},
page: {
height: 20,
alignItems: 'center',
},
header: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
backgroundColor: 'transparent',
overflow: 'hidden',
height: HEADER_MAX_HEIGHT,
},
backgroundImage: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
width: null,
height: HEADER_MAX_HEIGHT,
resizeMode: 'cover',
},
bar: {
backgroundColor: 'transparent',
marginTop: Platform.OS === 'ios' ? 28 : 38,
height: 32,
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
top: 0,
left: 0,
right: 0,
},
title: {
color: 'white',
fontSize: 18,
},
scrollViewContent: {
marginTop: HEADER_MAX_HEIGHT,
},
row: {
height: 40,
margin: 16,
backgroundColor: '#D3D3D3',
alignItems: 'center',
justifyContent: 'center',
},
});

Expo link for the same ,,
https://snack.expo.io/HyHCMrQvZ

Was this page helpful?
0 / 5 - 0 ratings

Related issues

itzsaga picture itzsaga  路  3Comments

karthikeyansundaram2 picture karthikeyansundaram2  路  3Comments

jouderianjr picture jouderianjr  路  3Comments

KingAmo picture KingAmo  路  3Comments

ios-dev-newbie picture ios-dev-newbie  路  3Comments