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?
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
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;
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;
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>
);
}
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)
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
if suppose one component has 10 line data and 2nd item has 2 line data then it breaks