Responsive Layouts In React Native Apps

Responsive Layouts In React Native Apps

How to create responsive apps on React Native and some best practices to implement it

With new electronic gadgets coming into the market every few months, managing responsiveness in an application is of prime importance to any web designer or Frontend developer. The web development community has contributed to creating multiple libraries for managing responsiveness and remove redundant boilerplate code but this is limited to web apps. How do we manage responsiveness on mobile apps is the topic that we are going to explore in this article.

Even though the majority of mobile apps are considered small in size, this difference in resolution and screen size doesn't make the challenge of handling responsiveness any easier. Android alone has phones which are built in different dimensions and with a range of screen resolutions and when you add iOS to the mix, this just about adds a whole layer of technicalities to take care of. Even if we can design a multi-platform app in a short time using React Native, the time taken for design and making the application look seamless can be quite long.

Let's discuss some ways through which we can make our apps more responsive and presentable.

Using Flexbox for Layout

Flexbox provides a method for layering out one-dimensional items horizontally or vertically; it adjusts the size and placement of items based on how they fit on the axis. The default value of display in React Native is flex and it works very similarly to how Flexbox works on the web with a few exceptions. The default direction of the axis here are column, alignContent defaults to flex-start instead of stretch, flexShrink defaulting to 0 instead of 1 and the flex parameter only supports a single number.

Using percentage

Using percentage instead of absolute values gives us the advantage of having our elements taking up minimal space i.e., if a View is supposed to take 10% of the screen then it will only cover that much space. There is just one downer though! Unlike web, some properties can't be given percentage values in React Native. These include borderRadius and borderWidth. Even though we can use other properties with percentages, not being able to use them with these properties does come up as a hurdle in our aim for maximum responsiveness.

Here is a pictorial representation on the Pixel 4 XL: Screenshot_1632236772.png

Here is a pictorial representation on the Pixel XL: Screenshot_1632297804.png

Here is a pictorial representation on the Nexus S: Screenshot_1632299215.png

Uniform set of values for margin and padding

This might not sound as technical as the previous points, but having a distinct set of values for spacing your elements makes your work a whole lot easier! Not only will you be able to make changes to your entire application through just one point, but all your elements will have symmetry and a crispness which can only be achieved through uniform spacing values!

Aspect Ratio

Aspect ratio is represented by the ratio between the width and the height of an image. It's only provided on React Native and is the most suitable property that controls the size of undefined element dimensions.

This property is used when our image is extending beyond screen dimensions and we need to rectify this error. The most basic example of implementing this is by using the 1:1 ratio. This value makes the image take up all the available space provided without overflowing outside the screen.

Here is a pictorial representation on the Pixel 4 XL: Screenshot_1632321886.png

Here is a pictorial representation on the Pixel XL: Screenshot_1632321978.png

Here is a pictorial representation on the Nexus S: Screenshot_1632323435.png

Screen Dimensions

Unfortunately for us, React Native does not provide an API to identify the details of a device, i.e. its type and screen size. However, the Dimensions API lets us get the width and height of the screen easily. Refer to the code given below:

import { Dimensions } from 'react-native';

const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;

With the introduction of Hooks, the useWindowDimensions is the recommended option for getting screen dimensions because it can automatically update the width and height of the screen when the screen changes so we don't have to worry about adding event listeners for it! Refer to the code given below:

import { useWindowDimensions } from 'react-native';

const { height, width } = useWindowDimensions();

Platform Detection

React Native has an amazing environment for building apps for both iOS and Android. However, due to the differences in native functionalities, we have to render different components based on what platform the device is using. This is where the Platform API comes into action by telling us the OS of the device. A common example of this is when we are using a native feature of an element that is not present in both platforms. Refer to the code given below:

import { Platform } from 'react-native';
Platform.OS === 'ios' ? <Text>My device is Apple</Text> : <Text>My device is Android</Text>

Device Screen Orientation

Although this discussed above, our main focus on this point would be to make sure our UI doesn't break when the device is rotated from portrait to landscape mode. With hooks, we don't need to implement an event listener; you can simply create effective and efficient conditional logic that would modify styles based on the device orientation.

Image scaling

The Image component of React Native provides us with an option of passing an array of sourceImage objects that includes source, width, and height of objects. What this will do is let the component decide which image to choose from the array based on its container size. Moreover, you can also add your own logic to customize this feature by measuring the width of the container on layout and using PixelRatio.getPixelSizeForLayoutSize to translate DIPs(Density Independent Pixels) into physical device pixels. Here's an example for a better explanation:

import tinyFlower from './assets/tinyFlower.png'
import largeFlower from './assets/largeFlower.png'

  const images = [
    Image.resolveAssetSource(tinyFlower),
    Image.resolveAssetSource(largeFlower),
  ]
  <Image style={styles.image} source={images} />

Font scaling

Even though font sizes are scaled automatically based on a device's pixel density to maintain maximum responsiveness, some tinkering with the fonts is still necessary. A section of text will look more crowded in a component if it is covering 50% of a small screen whereas the same text will look way more sparse in the same component on a larger screen.PixelRatio gives us access to the device's pixel density for scaling. The getFontScale method gives us some insight into the user's preference by returning the scaling factor for font sizes which is the ratio that is used to calculate the absolute font size; so any elements that heavily depend on this method should undergo some calculations. Refer to the code snippet given below:

import { PixelRatio } from 'react-native';

PixelRatio.getFontScale()

Conclusion

Hope these points helped you understand how responsiveness works and how we can make use of APIs provided by React Native for a better UI. These practices have been tried and tested by me and I hope it adds some value to your DevOps processes.