react-native-tab-view
react-native-tab-view copied to clipboard
Flex style ignored when tab view inside ScrollView
Current behavior
expo demo When putting a tab view inside a ScrollView, the tabs contents don't show unless you put a static height value, it seems to ignore flex
Example
<View style={{flex: 1}}>
<ScrollView style={{flex: 1}}>
<Text>Hello</Text>
<TabView
navigationState={{index, routes}}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={initialLayout}
style={{flex: 1}}
/>
</ScrollView>
</View>
With rendered scene
<View style={{flex: 1}}>
<Text>Hello</Text>
</View>
If I were to set the tabview style to height: 900
then it renders (although obviously with blank space underneath) but if I leave it as flex: 1 then nothing renders
Expected behavior
Flex should make the tab contents render in the remaining space of the screen
Reproduction
https://snack.expo.dev/66VUyv9e2
Platform
- [x] Android
- [X] iOS
- [ ] Web
- [ ] Windows
- [ ] MacOS
Environment
"dependencies": { "expo": "~44.0.0", "expo-status-bar": "~1.2.0", "react": "17.0.1", "react-dom": "17.0.1", "react-native": "0.64.3", "react-native-web": "0.17.1", "react-native-tab-view": "3.1.1", "react-native-pager-view": "5.4.9" },
The versions mentioned in the issue for the following packages differ from the latest versions on npm:
-
expo
(found:44.0.0
, latest:45.0.4
) -
react-native
(found:0.64.3
, latest:0.68.2
) -
react-native-pager-view
(found:5.4.9
, latest:5.4.17
)
Can you verify that the issue still exists after upgrading to the latest versions of these packages?
Tested with versions listed above and results are the same
I've narrowed down what seems to be causing the problem for me:
In SceneView, the style object for the main view is
{
"bottom": 0,
"height": undefined,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
"width": undefined,
},
and the main body is
{
focused || layout.width ? this.props.children({ loading }) : null
}
The position being absolute here means the children don't render, and the || layout.width
means that if the position is removed then the unfocused child is rendering in the background too, leaving blank space under the shorter children
@paulsjohnson91 Thanks for investigating this. This issue seems to also be affecting the Material Top Tabs Navigator in React Navigation. Were you able to find a temporary solution?
@DeveloperHarris unforunately I've not had time to investigate in detail, for now I've just forked the repo and removed both the position: absolute and the || layout.width
parts. This works fine for me as the above is my only use case for the tab view library however I haven't verified what would happen with other use cases yet. I will update if I can find a permanent solution
@DeveloperHarris unforunately I've not had time to investigate in detail, for now I've just forked the repo and removed both the position: absolute and the
|| layout.width
parts. This works fine for me as the above is my only use case for the tab view library however I haven't verified what would happen with other use cases yet. I will update if I can find a permanent solution
I found
{
// Only render the route only if it's either focused or layout is available
// When layout is not available, we must not render unfocused routes
// so that the focused route can fill the screen
focused || layout.width ? this.props.children({ loading }) : null
}
in SceneView.tsx, however, I wasn't able to find the style with the position:absolute or undefined height. @paulsjohnson91 do you remember what file those were located in?
Also, this occurs on android as well as ios, is it possible to update the tags?
The versions mentioned in the issue for the following packages differ from the latest versions on npm:
-
expo
(found:44.0.0
, latest:45.0.5
) -
react-native
(found:0.64.3
, latest:0.68.2
) -
react-native-pager-view
(found:5.4.9
, latest:5.4.24
)
Can you verify that the issue still exists after upgrading to the latest versions of these packages?
@DeveloperHarris
The position:absolute comes from the style object for the View in SceneView:
style={[
styles.route,
// If we don't have the layout yet, make the focused screen fill the container
// This avoids delay before we are able to render pages side by side
layout.width
? { width: layout.width }
: focused
? StyleSheet.absoluteFill
: null,
style,
]}
Specifically in the 'style' object above
I'm struggling to see where this style object is populated however I believe it comes from the types.tsx
and is populated using the react-native Animated library
export type SceneRendererProps = {
layout: Layout;
position: Animated.AnimatedInterpolation;
jumpTo: (key: string) => void;
};
I've now tested this with regular tab view not inside a tab view and removing the position option unfortunately doesn't work as it cuts off the bottom of the view.
It looks like we need position to be absolute when the tabview is not in a scrollview and to be undefined when it is.
I don't know if there's a better solution but maybe we could get a new TabView prop for nested
Just noticed the same issue occurs in this issue raised last year, which is loading a tab view into a modal
I'm running into this as well.
"react-native": "0.68.2", "@react-navigation/material-top-tabs": "^6.2.1", "react-native-tab-view": "^3.1.1",
Also running into this with react-navigation/material-top-tabs when trying to load it in a scrollview.
@react-navigation/material-top-tabs : "^6.2.1", "expo": "^45.0.0",
Also, have an issue with this. Does anyone have a current work around? Is there a better version of this library to downgrade to that is working?
I have a TabView not within a ScrollView, but each tab has it's own FlatList within it. First time I Load the FlatList are cut off at the bottom. If I navigate away and come back then the FlatList recalculate and it adjusts to the full height of the page. I'm assuming this is the same issue.
Downgrading to v2 seems to work for me.
The
I've narrowed down what seems to be causing the problem for me:
In SceneView, the style object for the main view is
{ "bottom": 0, "height": undefined, "left": 0, "position": "absolute", "right": 0, "top": 0, "width": undefined, },
and the main body is
{ focused || layout.width ? this.props.children({ loading }) : null }
The position being absolute here means the children don't render, and the
|| layout.width
means that if the position is removed then the unfocused child is rendering in the background too, leaving blank space under the shorter children
This style is from react-native-pager-view in utils.tsx
Changing
layout.width ? { width: layout.width } : focused ? StyleSheet.absoluteFill : null, style
to
layout.width ? { width: layout.width } : focused ? StyleSheet.absoluteFill : null, {overflow:'visible'}
Solved it for me. It is not a proper fix though.
Try adding contentContainerStyle={{ flexGrow: 1 }}
to the ScrollView:
<View style={{flex: 1}} >
{/* START FIX */}
<ScrollView style={styles.scene} contentContainerStyle={{ flexGrow: 1 }}>
{/* END FIX */}
<Text>Hello</Text>
<TabView
navigationState={{index, routes}}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={initialLayout}
style={{flex: 1}}
/>
</ScrollView>
</View>
Here's the modified snack above showing it working: https://snack.expo.dev/@aazcarraga/react-native-tab-view-nested-in-scroll-view
I spent a good amount of time myself trying to figure this one out, hope this helps!
I was running into a similar problem myself, implementing TabView
inside a SectionList
.
I ended up using patch-package, overriding SceneView
.
style={[
styles.route,
layout.width
? { width: layout.width }
: focused
? StyleSheet.absoluteFill
: null,
- style,
+ style?.[0]
// Only apply styles provided by sceneContainerStyle prop of TabView,
// ignoring absoluteFill from react-native-pager-view
]}
const styles = StyleSheet.create({
route: {
flex: 1,
- overflow: 'hidden',
+ overflow: 'visible',
// Default to visible
},
});
If absoluteFill
is needed, I pass it through sceneContainerStyle
with Stylesheet.absoluteFill
.
Try adding
contentContainerStyle={{ flexGrow: 1 }}
to the ScrollView:<View style={{flex: 1}} > {/* START FIX */} <ScrollView style={styles.scene} contentContainerStyle={{ flexGrow: 1 }}> {/* END FIX */} <Text>Hello</Text> <TabView navigationState={{index, routes}} renderScene={renderScene} onIndexChange={setIndex} initialLayout={initialLayout} style={{flex: 1}} /> </ScrollView> </View>
Here's the modified snack above showing it working: https://snack.expo.dev/@aazcarraga/react-native-tab-view-nested-in-scroll-view
I spent a good amount of time myself trying to figure this one out, hope this helps!
Thank you! This worked for me.
Try adding
contentContainerStyle={{ flexGrow: 1 }}
to the ScrollView:<View style={{flex: 1}} > {/* START FIX */} <ScrollView style={styles.scene} contentContainerStyle={{ flexGrow: 1 }}> {/* END FIX */} <Text>Hello</Text> <TabView navigationState={{index, routes}} renderScene={renderScene} onIndexChange={setIndex} initialLayout={initialLayout} style={{flex: 1}} /> </ScrollView> </View>
Here's the modified snack above showing it working: https://snack.expo.dev/@aazcarraga/react-native-tab-view-nested-in-scroll-view
I spent a good amount of time myself trying to figure this one out, hope this helps!
If you try to run it for iOS and Android you will see that this solution is still not working and it works only for Web
@arisyo13 Can you please send some demo of that, not working for iOS or Android? The @azcarraga's solution with adding contentContainerStyle={{ flexGrow: 1 }}
to <ScrollView />
seems to work.
Closing this, since adding contentContainerStyle={{ flexGrow: 1 }}
solves the issue. Thanks @mposborne 👍🏻
Try adding
contentContainerStyle={{ flexGrow: 1 }}
to the ScrollView:<View style={{flex: 1}} > {/* START FIX */} <ScrollView style={styles.scene} contentContainerStyle={{ flexGrow: 1 }}> {/* END FIX */} <Text>Hello</Text> <TabView navigationState={{index, routes}} renderScene={renderScene} onIndexChange={setIndex} initialLayout={initialLayout} style={{flex: 1}} /> </ScrollView> </View>
Here's the modified snack above showing it working: https://snack.expo.dev/@aazcarraga/react-native-tab-view-nested-in-scroll-view
I spent a good amount of time myself trying to figure this one out, hope this helps!
This is not working on android and IOS. Try scrolling on either device, you'll see it doesn't scroll - Better still, add an element below the scrollview.
As @amireds said, this does not work in native.
Does anyone got it working till now ?
@okwasniewski This issue is not resolved. Under most conditions, there are still the same problems.
@maximilize Let's reopen this. I will take a look at this one more time when I have time
the same
@okwasniewski just pinging to gauge if you think you'll have any time to look at this one again soon 🙏
@satya164 @okwasniewski Please could you look into this issue? Scrollview is not working when wrapped under tab view?