DEV Community

Saad
Saad

Posted on

Dynamic Height, Width, and Aspect Ratio in React Native

Let's say you are given this design to build a simple horizontal FlatList. How can you dynamically find the width and height of the items in the flat list? We can do it in different ways but recently in my code read journey I have learned a cool trick from my colleague. First of all, let's find the width of the item, shall we?

Alt text of image

As we can see from the above image, the whole screen width is 376 and if we inspect our item width in Figma (which is not shown in the above image), the item width is 240. So if we take this as our general measurement we can find out the item width according to screen width.

itemWidth = screenWidth * 376/240 OR screenWidth * 0.64
Enter fullscreen mode Exit fullscreen mode

Meaning that our items in the flat list are taking up 64% of the total width. So how do we define the height now? We can get the dynamic height from the width and aspect ratio.

// In Figma, our item width is 240 and height is 198
// so first we get the aspect ratio
const CARD_ASPECT_RATIO = 240 / 198; // aspectRatio = width / height
const CARD_WIDTH = Metrics.screenWidth * 0.64; // this we already found out
const CARD_HEIGHT = CARD_WIDTH / CARD_ASPECT_RATIO;
Enter fullscreen mode Exit fullscreen mode

Following the same method we can find out the inner content height and width. In our case, we have a top section with empty background and bottom section with text inside it. So in order to get the top section height and width dynamically, we can use the same formula.

const IMAGE_CONTAINER_ASPECT_RATIO = 240 / 140;
const IMAGE_CONTAINER_WIDTH = CARD_WIDTH;
const IMAGE_CONTAINER_HEIGHT = IMAGE_CONTAINER_WIDTH / IMAGE_CONTAINER_ASPECT_RATIO;
Enter fullscreen mode Exit fullscreen mode

Finally, if we put it all together it will look like this in the following:

import * as React from 'react';
import { Text, View, StyleSheet, FlatList, Dimensions } from 'react-native';
import { Card } from 'react-native-paper';

const { width, height } = Dimensions.get('window');

const Metrics = {
  section: 16,
  halfSection: 8,
};

const CARD_WIDTH = width * 0.64;
const CARD_ASPECT_RATIO = 240 / 198;
const CARD_HEIGHT = CARD_WIDTH / CARD_ASPECT_RATIO;
const IMAGE_CONTAINER_ASPECT_RATIO = 240 / 140;
const IMAGE_CONTAINER_WIDTH = CARD_WIDTH;
const IMAGE_CONTAINER_HEIGHT =
  IMAGE_CONTAINER_WIDTH / IMAGE_CONTAINER_ASPECT_RATIO;

const styles = StyleSheet.create({
  topCars: {
    height: CARD_HEIGHT,
    width: CARD_WIDTH,
    borderRadius: 12,
    marginRight: Metrics.halfSection,
  },

  topCarsImage: {
    width: IMAGE_CONTAINER_WIDTH,
    height: IMAGE_CONTAINER_HEIGHT,
    borderRadius: 12,
    borderBottomLeftRadius: 0,
    borderBottomRightRadius: 0,
  },
});

export default function App() {
  return (
    <View style={{ flex: 1, paddingTop: 48 }}>
      <FlatList
        showsHorizontalScrollIndicator={false}
        contentContainerStyle={{
          paddingHorizontal: Metrics.section,
          paddingBottom: Metrics.section,
        }}
        horizontal={true}
        data={[
          {
            name: 'KFC',
            location: 'Bukit Bintang, Kuala Lumpur',
            bg: 'cyan',
          },
          {
            name: 'MacDonalds',
            location: 'Damansara, Kuala Lumpur',
            bg: 'orange',
          },
          {
            name: 'Pizza Hut',
            location: 'Damansara Jaya, Kuala Lumpur',
            bg: 'yellow',
          },
          {
            name: 'Pak Punjab',
            location: 'Bukit Heights, Kuala Lumpur',
            bg: 'grey',
          },
        ]}
        keyExtractor={(item, index) => index.toString()}
        renderItem={({ item, index }) => {
          return (
            <Card style={styles.topCars}>
              <View
                style={[styles.topCarsImage, { backgroundColor: item.bg }]}
              />
              <View style={{ padding: 12 }}>
                <Text>{item.name}</Text>
                <Text>{item.location}</Text>
              </View>
            </Card>
          );
        }}
      />
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode

Also if you would like to see it in action, please check out the snack link.
https://snack.expo.io/@saad-bashar/dynamic-height-and-width

Top comments (2)

Collapse
 
christopherdcosta profile image
ChristopherDcosta

Hey Saad
That was a wonderful and informative post about responsiveness.

However, I've got a doubt. How did you calculate 376 / 240 equivalent to 0.64?
Waiting for your response at the earliest

Collapse
 
nikhilmasurkar profile image
NikhilMasurkar • Edited

if suppose one component has 10 line data and 2nd item has 2 line data then it breaks