Skip to content
This repository has been archived by the owner on Nov 27, 2022. It is now read-only.

Flex style ignored when tab view inside ScrollView #1349

Closed
2 of 5 tasks
paulsjohnson91 opened this issue May 19, 2022 · 38 comments
Closed
2 of 5 tasks

Flex style ignored when tab view inside ScrollView #1349

paulsjohnson91 opened this issue May 19, 2022 · 38 comments

Comments

@paulsjohnson91
Copy link

paulsjohnson91 commented May 19, 2022

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

  • Android
  • 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"
},

@github-actions
Copy link

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?

@paulsjohnson91
Copy link
Author

Tested with versions listed above and results are the same

@paulsjohnson91
Copy link
Author

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

@DeveloperHarris
Copy link

@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?

@paulsjohnson91
Copy link
Author

@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
Copy link

DeveloperHarris commented Jun 5, 2022

@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?

@github-actions
Copy link

github-actions bot commented Jun 7, 2022

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?

@paulsjohnson91
Copy link
Author

@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

@paulsjohnson91
Copy link
Author

Just noticed the same issue occurs in this issue raised last year, which is loading a tab view into a modal

@ajstokar
Copy link

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",

@MikaDeVries
Copy link

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",

@himrocks33
Copy link

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?

@himrocks33
Copy link

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.

@KeaganStevens
Copy link

Downgrading to v2 seems to work for me.

@KeaganStevens
Copy link

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

@KeaganStevens
Copy link

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.

@azcarraga
Copy link

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!

@karlerikjonatan
Copy link

karlerikjonatan commented Jul 8, 2022

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.

@mposborne
Copy link

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.

@arisyo13
Copy link

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

@szymonrybczak
Copy link
Contributor

@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.

@okwasniewski
Copy link
Collaborator

Closing this, since adding contentContainerStyle={{ flexGrow: 1 }} solves the issue. Thanks @mposborne 👍🏻

@amireds
Copy link

amireds commented Sep 1, 2022

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.

@mtourj
Copy link

mtourj commented Sep 14, 2022

As @amireds said, this does not work in native.

@kunalkumar007
Copy link

Does anyone got it working till now ?

@maximilize
Copy link

@okwasniewski This issue is not resolved. Under most conditions, there are still the same problems.

@okwasniewski
Copy link
Collaborator

@maximilize Let's reopen this. I will take a look at this one more time when I have time

@okwasniewski okwasniewski reopened this Sep 20, 2022
@thanhdevapp
Copy link

the same

@cam-shaw
Copy link

cam-shaw commented Oct 26, 2022

@okwasniewski just pinging to gauge if you think you'll have any time to look at this one again soon 🙏

@quicksilverr
Copy link

quicksilverr commented Oct 27, 2022

@satya164 @okwasniewski Please could you look into this issue? Scrollview is not working when wrapped under tab view?

@thraxxdv
Copy link

thraxxdv commented Nov 8, 2022

Same issue but implemented using @react-navigation/material-top-tabs

I have a ScrollView with a cover photo and the bottom of that are tabs:

<ScrollView>
     <CoverPhoto/>
     <Tabs />
</ScrollView>

@iainmck
Copy link

iainmck commented Nov 9, 2022

Seeing this in @react-navigation/material-top-tabs as well when I place the Tab view inside a SafeAreaView.
You can see the components colored here, which demonstrates the improper size of the tab container.

I have a satisfactory workaround which is overflow: 'visible', though a solution that sets proper height would be great.

<Tab.Navigator 
  style={{flex: 1, backgroundColor: 'red'}}
  sceneContainerStyle={{backgroundColor: 'blue', flex: 1, overflow: 'visible'}}
>
    <Tab.Screen name="Posts 🎨" component={PostsTab} />
    ...

IMG_2A9DFB1A04F4-1

@danielaloycedaniel
Copy link

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.

This worked to me but I left overflow hidden as it was. I only changed style to style?.[0]

@vlkpa
Copy link

vlkpa commented Nov 18, 2022

Same with nested ScrollViews

<ScrollView>
     <CoverPhoto/>
     <ScrollView>
         <Tabs />
      </ScrollView>
</ScrollView>

Same issue but implemented using @react-navigation/material-top-tabs

I have a ScrollView with a cover photo and the bottom of that are tabs:

<ScrollView>
     <CoverPhoto/>
     <Tabs />
</ScrollView>

@okwasniewski
Copy link
Collaborator

I think what you are trying to achieve can be done using this library.

Unfortunately at the moment we are not planning to support this. It's not possible to measure height of content inside of ScrollView (without some hacky workarounds), you can achieve it with this library by setting an explicit height.

Also since we are trying to make this library easy to maintain (and contribute to) this does not correlate with the main idea to display simple tab view. Therefore I'm closing all issues regarding embedding tab-view inside of ScrollView.

@dylmye
Copy link

dylmye commented Nov 18, 2022

Therefore I'm closing all issues regarding embedding tab-view inside of ScrollView.

If this common usecase is no longer supported, should the README be updated with the above information?

@okwasniewski
Copy link
Collaborator

If this common usecase is no longer supported, should the README be updated with the above information?

@dylmye The information about ScrollView not being supported, have been there the whole time. You can check it here: https://github.com/satya164/react-native-tab-view#avoid-rendering-tabview-inside-scrollview

@okwasniewski okwasniewski closed this as not planned Won't fix, can't repro, duplicate, stale Nov 19, 2022
@dylmye
Copy link

dylmye commented Nov 21, 2022

@okwasniewski "will disable the optimizations" is different from "doesn't show at all" though :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests