Build responsive React Native views for any device and support orientation change

Responsive UI is definitely an important part of web and mobile development. When I started working with React Native more than a year ago, I discovered the hard way that there is no functionality out of the box to support responsiveness.
The goal of this article is to show a complete solution that scales RN UI to all sizes and types of screens (phones, tablets etc) and also supports UI scaling even when the app changes orientation.
How React Native works and what are the problems
React Native style properties accept either percentage or independent pixel (dp) values.
Percentage
Percentage is what we know from “normal” web development. The problem with it, is that not all RN style properties accept it. In example: margin
, border-width
, border-radius
and many properties do not accept it as value.
That being said, there is no option for a developer to make their app responsive by coding everything in percentage…
Independent pixels
Independent pixels (dp) on the other hand, are not the classic screen pixels (px) that we become accustomed to as web developers. They mathematically connect to screen pixels and the screen’s scale factor through the following equation:
px = dp * scaleFactor
DP can not be used for responsive UI development as someone might think at this point. That is because scaleFactor
actually depends on screen’s pixel density, meaning the number of pixels per inch (ppi). What RN can do though, is that it can scale dp values to screen of different sizes only if they have the same number of ppi. But if you think of Android phones — there are thousands out there and most of them have screens with different ppi even if they come from the same manufacturer!
For more info regarding screens and UI factors, you can have a look at Android’s guide for pixel densities here, Android’s screen compatibility overview and paintcodeapp’s guide for iPhone resolutions.
Let’s come up with a solution — let’s introduce package react-native-responsive-screen
The idea is really simple! Let’s emulate ourselves the percentage effect, and provide the “correct” dp value for every different screen dynamically. We coded that small and easy solution into a package called react-native-responsive-screen.`
UI responsiveness
In order to create responsive UIs, you need to import and use these 2 methods called widthPercentageToDP
and heightPercentageToDP
. The names are a bit big but they try to be indicative. That being said, both methods accept a string like percentage ('30%'
) as an argument and return the percentage of the screen’s actual width or height respectively in dp.
Let’s see this with an example. Samsung A5 2017 Android phone, has a width of 360 dp (this is without taking the scale factor into account); so if we code the following:
<View style={{width: widthPercentageToDP('53%')}} />
it will be translated to:
<View style={{width: 190.8} />
because 53% * 360 dp = (53/100) * 360 dp = 190.8 dp. So if you include these 2 methods within your style process, they will automatically find the correct dp values for every single device. And that happens in a performant way; the package makes sure to calculate screen’s width and height once when the app is initialized and every time the methods are used it simply calls these values to make the calculation instead of identifying them again.
Let’s see a 2nd more detailed example:
import React from 'react';
import { StyleSheet, Text, View, Dimensions } from 'react-native';
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<View style={styles.responsiveBox}>
<Text style={styles.text}>This box is always of 84.5% width and 17% height.</Text>
<Text style={styles.text}>Test it by running this example repo in phones/
emulators with screens of various dimensions and pixel per inch (ppi).</Text>
</View>
</View>
);
}
}const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'gray',
alignItems: 'center',
justifyContent: 'center',
},
responsiveBox: {
width: wp('84.5%'),
height: hp('17%'),
borderWidth: 2,
borderColor: 'orange',
flexDirection: 'column',
justifyContent: 'space-around'
},
text: {
color: 'white'
}
});
What happens here is that we create a simple screen with some text and a view wrapper around it. We code the wrapper’s height to always be the 70% of the screen’s width and the 80% of the screen’s height. Finally we used smaller aliases for the methods’ big names. Check the cross screen result below:

Let’s see a 3rd example of a real production Android app:


Guidelines on how to use these methods
- After the package has installed and when the application loads, it detects the screen’s width and height. I.e. for Samsung A5 2017 phone, it detects
width: 360DP
andheight: 640DP
(these are the values without taking into account the device's scale factor). - Methods
widthPercentageToDP
andheightPercentageToDP
can be used for any style (CSS) property that accepts DP as value. Properties with DP values are the ones of typenumber
over the props mentioned in RN docs: View style props, Text style props, Image style props, Layout props and Shadow props. Use the exposed methods for all of the typenumber
properties used in your app in order to make your app fully responsive for all screen sizes. - You can also provide decimal values to these 2 methods, i.e.
font-size: widthPercentageToDP('3.75%')
. The package methods can be used with or without flex depending on what you want to do and how you choose to implement it. - The suggested approach is to start developing from larger screens (i.e. tablets). That way you are less prone to forget adding responsive values for all properties of type
number
. In any case, when your screen development is done, you should test it over a big range of different screens as shown below in the How do I know it works for all devices ? section.
Orientation change support
If you want for your application to detect orientation change and adapt the UI itself, you simply need to add an extra listener . This translates into an additional 2 methods: listenOrientationChange
that adds the event listener for detecting device orientation change and removeOrientationListener
that removes the listener in order not to add new listeners in case the screen is re-mounted (that could lead to performance issues and potential app crashes). To see how to use them, check the example below.
Let’s see how we can add orientation support to our previous example:
import React from 'react';
import { StyleSheet, Text, View, Dimensions } from 'react-native';
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
listenOrientationChange as loc,
removeOrientationListener as rol
} from 'react-native-responsive-screen';
export default class App extends React.Component {
componentDidMount() {
loc(this);
}
componentWillUnMount() {
rol();
}render() {
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'gray',
alignItems: 'center',
justifyContent: 'center',
},
responsiveBox: {
width: wp('84.5%'),
height: hp('17%'),
borderWidth: 2,
borderColor: 'orange',
flexDirection: 'column',
justifyContent: 'space-around'
},
text: {
color: 'white'
}
});
return (
<View style={styles.container}>
<View style={styles.responsiveBox}>
<Text style={styles.text}>This box is always of 84.5% width and 17% height.</Text>
<Text style={styles.text}>Test it by running this example repo in phones/
emulators with screens of various dimensions and pixel per inch (ppi).</Text>
</View>
</View>
);
}
}
What happened now?
1. We added the orientation change listener in componentDidMount
lifecycle method.
2. We added the orientation change listener remover in componentWillUnmount
lifecycle method. This is a crucial step, because if we don’t do it, a new listener will be registered every time the component re-mounts and can lead to performance issues or even application crash.
3. styles
object is created inside the render lifecycle method. That is because every time the listener detects the orientation change it triggers a re-render and thus the styles will be re-created.
And the result looks like that:

The code behind the package
If you want to check the source code of these methods and how they work have a look below. The code is actually pretty small and that’s what triggered me to create a package out of them; a small, easy to use package for responsiveness.
Comments
Post a Comment
Thank You.