3

Currently I am using this package https://github.com/satya164/react-native-tab-view, but I have also tried with this one from react navigation https://reactnavigation.org/docs/material-top-tab-navigator/ and having the same problem.

Basically I am trying to remove the default flexbox behaviour "Equal Height Columns"

Introduction

I am implementing a tab view that has three scenes. The first one is going to be a screen with an endless and paginated flatlist (its height is undetermined) and the others two has their own view with a determined height.

Problem

When the content of the first tab is rendered its height is good, but when an other tab is rendered and its height is greater than the first one, it (the first tab) changes its height to the other tab's height.

The first tab can have +100000 items, but suppose that, currently, it only has 1 item which size is 30px. The second tab has an immutable height of 40px, and the last one 50px.

With my current code, this is what happens:

The purple space shouldn't appear

The purple space shouldn't appear!!

Code

As the code is long, I have commented "<--------" in the relative parts.

export default function Tab(props) {
  const [index, setIndex] = useState(0);
  const [tab1Height, setTab1Height] = useState(null);
  const [tab2Height, setTab2Height] = useState(null);


  const [routes] = useState([
    { key: "tab0", title: "Tab0" },
    { key: "tab1", title: "Tab1" },
    { key: "tab2", title: "Tab2" },
  ]);

  const handleTabHeights = (height, tabIndex) => { // <--------
     // Do nothing if no height
     if (height <= 0) return;

     switch (tabIndex) {
       case 1:
         setTab1Height(height);
         return;
       case 2:
         setTab2Height(height);
         return;
       default:
         return;
     }
   };

 const renderScene = ({ route }) => { // <--------
    switch (route.key) {
      case "tab0":
        return <EndlessScreen {...this.props} />; // <---- Not handling the scene height because it is undetermined (can be 0, 1000, 30, 9000... any value, and can change in some item is added to the flatlist)
      case "tab1":
        return (
          <View
            onLayout={(event) => // <-------
              handleTabHeights(event.nativeEvent.layout.height, 1)
            }
          >
            <View style={{ height: 40, backgroundColor: "lime" }} {...this.props} />
          </View>
        );
      case "tab2":
        return (
          <View
            onLayout={(event) => // <---------
              handleTabHeights(event.nativeEvent.layout.height, 2)
            }
          >
             <View style={{ height: 50, backgroundColor: "red" }} {...this.props} />
          </View>
        );
      default:
        return null;
    }
  };

 // ... other stuff

 return (
    <TabView
      style={ // <-----------
        index === 0
          ? { flex: 1, backgroundColor: "purple" } <--------- THINKS THAT HERE IS THE PROBLEM
          : {
              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}
      lazy={false}
    />
  );

What I think the problem is

I think that I have to dynamically get the height of the flatlist using onLayout and updating state, but this will cause multiple state updates, and will affect the performance a lot.

There has to be an other way to handle this, I mean, some css or flex attribute (or something) to make the first tab adapt its height correctly to its flatlist.

Observation

If the first tab has the biggest height, everything is perfect, all tabs has their respective heights.

What I have tried

I have tried to dynamically get the height of the FlatList but this is too difficult, because useState is async and the onLayout prop is not called when the user adds or removes one item to the flatlist...

Any ideas? I would really appreciate your help.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Victor Molina
  • 2,353
  • 2
  • 19
  • 49
  • Possible guidance: https://stackoverflow.com/q/33034660/3597276 – Michael Benjamin Aug 29 '20 at 23:29
  • I tried too but nope – Victor Molina Aug 30 '20 at 06:53
  • I have solved this with a trick, just when tab 0 is on screen, I remove tab 1 and 2 from the flexbox, and when tab 1 or 2 are on screen, I don't remove any tab because they have their own height (dinamically calculated). The problem is that it can be an ugly transition when sliding from tab 0 to 1, but works fine... Also, as in tab 1 and 2 I made fetches to my db, I have had to move all this logic to a parent component which doesn't unmount. Not the best solution but I prefer this to measure an endless and dynamic list. – Victor Molina Aug 30 '20 at 18:50

0 Answers0