cssreact-nativeflexboxreact-native-flatlist

React Native FlatList: How to vertically center content below a fixed header in renderItem?


I'm building an intro slider in React Native using a horizontal FlatList. Each slide consists of:

The problem is that the image and description block stay aligned at the top instead of centering vertically, even though I've applied flex: 1 and justifyContent: 'center' to their container.

   <FlatList
  data={slides}
  horizontal
  pagingEnabled
  renderItem={({ item }) => (
    <View style={[styles.slide, { width }]}>
      <View style={styles.titleContainer}>
        <Text style={styles.title}>{item.title}</Text>
      </View>
      <View style={styles.contentWrapper}>
        <item.SlideImage style={styles.image} />
        <Text style={styles.desc}>{item.descr}</Text>
      </View>
    </View>
  )}
/>

const styles = StyleSheet.create({
  slide: {
    flex: 1,
    alignItems: 'center',
    flexDirection: 'column',
    // justifyContent: 'center', // removed to keep title at top
  },
  titleContainer: {
    height: 60,
    justifyContent: 'center',
    alignItems: 'center',
  },
  contentWrapper: {
    flex: 1,
    justifyContent: 'center', // intended to center vertically
    alignItems: 'center',
    width: '100%',
    paddingHorizontal: 20,
  },
  title: { fontSize: 26, fontWeight: '700', textAlign: 'center' },
  image: { width: 300, height: 300 },
  desc: { fontSize: 16, textAlign: 'center', marginTop: 12, color: '#555', lineHeight: 22 },
});

I’ve tried several things:

Outline debugging:

enter image description here

Still, the content inside contentWrapper stays stuck at the top and won’t center vertically.

Why doesn’t the contentWrapper take all the available vertical space to center its children? How can I fix this layout issue?


Solution

  • To vertically center the image + description block only in the space below the title, you just need to make sure that:

    1. the wrapper that contains the content (contentWrapper) has flex: 1, so it takes all the remaining space below the header, and

    2. you use justifyContent: 'center' to center its children vertically inside that space.

    In your code you were already almost there — the only missing piece is that the title container above must not grow (so it doesn’t steal space), while the content wrapper must grow.

    
    <View style={[styles.slide, { width }]}>
      <View style={styles.titleContainer}>
        <Text style={styles.title}>{item.title}</Text>
      </View>
    
      <View style={styles.contentWrapper}>
        <item.SlideImage style={styles.image} />
        <Text style={styles.desc}>{item.descr}</Text>
      </View>
    </View>
    
    Now make sure the styles look like this:
    
    titleContainer: {
      // DON'T add flex here, or it will take unnecessary space
      paddingTop: 40,            // your fixed top offset
      paddingBottom: 20,
    },
    
    contentWrapper: {
      flex: 1,                   // <– grows to fill the rest of the slide
      justifyContent: 'center',  // <– vertical centering
      alignItems: 'center',
      paddingHorizontal: 20,
    }