React Native选项卡视图的高度始终等于最高选项卡的高度

3

介绍

我有一个FlatList,在其页脚中呈现一个选项卡视图。该选项卡视图允许用户在一个FlatList或另一个FlatList之间切换。所以这些FlatLists是同级的。

问题

第一个FlatList "A" 的高度大于第二个FlatList "B"。当我选择第二个列表时,它的高度与"A" FlatList的高度相同。

我已经在食品盒(Snack)中复制了此问题,您可以看到类似的代码。我承认代码有点长但非常简单,只需专注于父FlatList(在App组件中)和在每个选项卡中呈现的两个FlatLists(在代码末尾)

问题

有什么想法解决这个问题吗?我不知道问题是样式还是我必须做其他事情才能使其正常工作(所有FlatLists都必须具有自己的高度,而不是更大的高度)。

谢谢,我真的很感激您的帮助。


为什么在FlatList页脚中需要一个选项卡? - rishikesh_07
因为当我滚动时,标题栏和选项卡栏也应该向上移动。 - Victor Molina
3个回答

6

更新于2022年

  const renderScene = ({ route }) => {
    //
    //  Note: We are hidding tabs in order to avoid the
    // "FlexBox Equal Height Columns" typical problem
    //
    switch (route.key) {
      case "bitcoin":
        return (
          <View style={index !== 0 && styles.hidden}>
            <Bitcoin />
          </View>
        );

      case "ethereum":
        return (
          <View style={index !== 1 && styles.hidden}>
            <Etherum />
          </View>
        );

      case "rose":
        return (
          <View style={index !== 2 && styles.hidden}>
            <Rose />
          </View>
        );

      default:
        return null;
    }
  };


...

<TabView
  renderTabBar={renderTabBar}
  navigationState={{ index, routes }}
  renderScene={renderScene}
  onIndexChange={handleOnIndexChange}
  initialLayout={{ width: layout.width }}
  removeClippedSubviews={false}
  swipeEnabled
  swipeVelocityImpact={0.2}
  gestureHandlerProps={{
    activeOffsetX: [-30, 30], // To solve swipe problems on Android
  }}
  style={globalStyles.flexContainer}
/>

样式:

hidden: { display: "none" }

我已更新小吃点的解决方案!

由于在小吃点中我实现了自己的TabView,因此我决定使用库“react-native-tab-view”来实现相同的解决方案,因为它是目前最好的适用于React Native的标签。

想一想,一些遇到这个问题的人将能够解决它。

基本上,我们需要做的就是动态计算每个选项卡场景的高度,并将其传递给TabView的样式,使用onLayout属性就可以了。

就像这样:

 const renderScene = ({ route }) => {
    switch (route.key) {
      case "inifiniteScrollFlatList":
        return (
          <FirstRoute />
        );
      case "rawDataFlatList":
        return (
          <View
            onLayout={(event) => setTab1Height(event.nativeEvent.layout.height + TAB_HEIGHT)}
          >
            <SecondRoute />
          </View>
        );
      case "otherRawDataFlatList":
        return (
          <View
            onLayout={(event) => setTab2Height(event.nativeEvent.layout.height + TAB_HEIGHT)}
          >
            <ThirdRoute />
          </View>
        );
      default:
        return null;
    }
  };

  <TabView
      style={ index !== 0 && {
        height: index === 1 ? tab1Height : tab2Height,
      }}
      renderTabBar={renderTabBar}
      navigationState={{ index, routes }}
      renderScene={renderScene}
      onIndexChange={setIndex}
      initialLayout={initialLayout}
      removeClippedSubviews={false} // Pd: Don't enable this on iOS where this is buggy and views don't re-appear.
      swipeEnabled={true}
  />

注意:对于使用无限滚动和分页的选项卡,您不应该这样做。相反,您需要将高度设置为null ,以允许父FlatList自动获取其高度。


1
2022年的更新非常棒,而且仍然很相关。感谢那个解决方案 - 这是我唯一能够让它工作的方法! - kekkles4
谢谢 - 隐藏选项卡的解决方案仍然是最佳解决方案 - 我希望它能够内置 :) - 手势在现代用户界面中很少使用,因此保留它仅用于支持手势不太合理。此外,在Web中,对选项卡视图进行样式化高度无效,这使得更新后的解决方案变得更糟。奇怪的是,其他属性(如backgroundColor)确实有效。不知道为什么,文档也没有提到。 - howard

1

最终我把选项卡控件的标签内容全部删除了。这样做有些取巧,但对我来说起到了作用...

 render() {
const {index} = this.state;
return (
  <ScrollView>
    <TabView
      renderPager={this._renderPager}
      renderScene={() => null}
      onIndexChange={index => this.setState({index})}
      initialLayout={{height: 0, width: Dimensions.get('window').width}}
    />
    {index === 0 && <Tab1Content />}
    {index === 1 && <Tab2Content />}
  </ScrollView>
);

来源:- https://github.com/satya164/react-native-tab-view/issues/290#issuecomment-447941998

这个问题的解决方法是在每个标签页中使用相同的键来存储它们的状态。如果你为每个标签页使用不同的键,则会导致状态丢失和混淆,因为每个标签页都会有自己的状态副本。
所以,确保在所有标签页之间使用相同的键来存储它们的状态,就可以避免这个问题。

我曾经使用过这个解决方案,但是由于多次重新挂载而导致了一些性能问题...最好的方法(至少是我现在正在使用的方法)是使用 display: "none"(请查看更新 ;)) - Victor Molina

1
所以,我没有完整地查看代码,也没有找到解决您高度问题的方法。但是,您可以查看React Navigation 5 -> createMaterialTopTabNavigator。它允许您为每个选项卡创建单独的Flatlist选项卡,这将解决高度问题,因为正在呈现的是每个活动选项卡的单独Flatlists。而且,它还将使您的代码更加清晰。您不必使用带有标题和页脚组件的Flatlist来呈现嵌套Flatlists的选项卡。如果您想要在滚动时隐藏选项卡,则可以通过向选项卡导航器传递属性来实现,该属性使用onScroll事件,在滚动Flatlist时切换可见性。对于标题的可见性也可以做同样的事情。通过适当的动画,它看起来就像是在滚动时将标题和选项卡向上推,就像现在一样。

实际上我需要在父FlatList中渲染选项卡和标题。这是因为当刷新时,父FlatList将获取Tab2和Tab3的数据,而Tab1具有其自己的数据库监听器。这就是为什么我像这样实现它。如果我将选项卡从React Navigation 5嵌套,我能解决高度问题吗? - Victor Molina
在我的零食项目中,我实现了自己的选项卡,但在我的真实代码中,我正在使用“react-native-tab-view”,它被React Navigation 5使用,并且仍然存在相同的问题。我已经在https://github.com/satya164/react-native-tab-view/issues/290上阅读了这个问题,库的实现者说:“没有什么特别的,你可以使用onLayout测量组件的布局并使用样式设置高度。” - Victor Molina
1
你可以解决高度问题,但是你不能将那些选项卡移到中心。它们位于 Stack 导航器标题的顶部和底部。但是,我可能错了,因为我没有尝试将这些选项卡移动到屏幕中心。你可以做的是使 Stack 导航器的标题与你想要的标题完全相同。这样,选项卡就会移动到你想要它们在的位置(屏幕中心),并且在选项卡处于活动状态时调用单独的组件中的 flatlists。这实际上可能有效。但是,这将需要大量的工作。它应该可以解决高度问题。 - Tom Bombadil
是的,堆栈标题有一个属性可以切换其可见性。你可能可以使用它,但我不太确定。但是,关键在于正确设置动画,以在滚动时提供平滑的用户体验,并使堆栈标题和顶部选项卡向上滑动并随着滚动变得不可见。说实话,这需要太多的工作。但是,我找到了这个链接:https://dev59.com/yFgR5IYBdhLWcg3wAJBK,也许它可以帮助你正确设置动画。 - Tom Bombadil
我已经解决了这个问题。由于我不想在我的子组件上引起重新渲染,所以我必须动态计算高度并使用onLayout属性进行设置。您可以在没有堆栈的情况下使用此功能,在父FlatList上拥有刷新控件(在我的用例中,此父FlatList获取两个选项卡的数据,因此我需要显示一个刷新控件)。 - Victor Molina
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接