Flex React Native FlatList children to grow to full height?
Asked Answered
K

3

10

I'm using FlatList from React Native to render a bunch of items stacked on top of each other.

This works fine, I've managed to make the FlatList itself expand it's height to fill the available space but I want the FlatList items to grow when there is more space available.

This was simple to do using ScrollView (simplified pseudocode):

<ScrollView
  contentContainerStyle={{
    display: "flex",
    flexGrow: 1,
  }}
>
  <Item key={1} style={{ flexGrow: 1 }} />
  <Item key={2} style={{ flexGrow: 1 }} />
</ScrollView>

However it doesn't work for FlatList (simplified pseudocode):

<FlatList
  contentContainerStyle={{
    display: "flex",
    flexGrow: 1,
  }}
  renderItem={({ index }) => <Item key={index} style={{ flexGrow: 1 }} />}
/>

I've created an Expo Snack showing both the ScrollView successfully growing the elements and the FlatList failing to do so.

There seems to be a lot of discussion online about making the parent FlatList full height, but I've struggled to find anything about making the FlatList items grow to fill the available FlatList height.

I need to use FlatList as I plan to use react-native-draggable-flatlist to implement drag and drop and cannot find an equivalent library that doesn't use FlatList.

A screenshot of the Expo Snack is shown here: Screenshot showing example of ScrollView items growing to fill available height but FlatList items failing to do the same

As seen here, it seems the offending issue in the DOM is the CallRenderer, the VirtualizedList is the right height with the right flex styling, and DayItem is set to grow (and worked fine with ScrollView), but in between there's the CallRenderer which seems to interrupt the flex relationship between the two:

Screenshot inspecting VirtualizedList Screenshot inspecting CallRenderer Screenshot inspecting FlatList child item

Any help is much appreciated.

Keramic answered 20/3, 2021 at 21:43 Comment(2)
If you set a minHeight: screen to the flatlist it might help with thatPresocratic
@Presocratic the FlatList itself is already growing to the height available, it's just the items inside that won't grow (despite parent being flex and the children being flexGrow: 1, seems CallRenderer is breaking the flex setupKeramic
M
4

As a workaround, you can listen to onLayout of the Flatlist, hold the calculated height in a state, and then set each child's height to flatlist height / data.length.

Magnetism answered 20/3, 2021 at 23:35 Comment(1)
hmm this could work with minHeight as a backup plan, hoping to fix it with CSS only but will bear in mind, thanks!Keramic
L
1

I found the best method to accomplishing this is to divide the height of the screen or in the case of your example the height of flatlist itself by the number of list items (or the number of items you would like to fill the screen at a time) and set that as the height of renderItem:

 const items = [ { text: "First item" }, { text: "Second item"} ];

 // height given to flatlist
 const FLATLIST_HEIGHT= 200;

 // or number of Items I want to fill screen
 const ITEMS_COUNT = items.length;

 const renderItem = ({ item, index, drag, isActive }) => {
    return (
      <View
        style={{
          borderWidth: 2,
          height: Math.floor(FLATLIST_HEIGHT/ITEMS_COUNT) - 2,
          // minus 2 to compensate for borderWidth
        }}
      >
        <Text>{item.text}</Text>
      </View>
    );
  };

...

 const myFlatList = (
    <FlatList
      data={items}
      renderItem={renderItem}
      keyExtractor={item => item.id}
      contentContainerStyle={{
        height: FLATLIST_HEIGHT,
      }}
    />
  );

In cases where no flatlist fills up the screen simply set the value of the window height:

import {..., Dimensions} from 'react-native';

...
const HEIGHT = Dimensions.get('window').height;

const renderItem = ({ item, index, drag, isActive }) => {
    return (
      <View
        style={{
          borderWidth: 2,
          height: Math.floor(HEIGHT/ITEMS_COUNT) - 2,
          // minus 2 to compensate for borderWidth
        }}
      >
        <Text>{item.text}</Text>
      </View>
    );
  };
Larder answered 26/3, 2021 at 23:27 Comment(0)
G
0

make each item flex: 1 not the flatlist

Gillie answered 23/3, 2021 at 10:42 Comment(6)
thanks for the reply Ehsan, but the items already have flexGrow: 1 on them, setting the shorthand flex: 1 only sets flexShrink and flexBasis and when trying that out it doesn't make a difference here. can see the code here: snack.expo.io/@fredrivett/…Keramic
seems strange? would you mind to please check the inner details of the flatlist you can figure it out how it works internallyGillie
I think because of performance. flatlist always assign a calculated height for every item.Gillie
one workaround is to divide number of item on the height of the flatlistGillie
or you can open an issue on github.Gillie
yeah I agree it it probably by design for performance, but hadn't seen anything from my research mentioning this yet. I may have to open an issue on github but thought this was more of a question than a bug/limitation. will ask there too, cheers!Keramic

© 2022 - 2024 — McMap. All rights reserved.