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