Sei sulla pagina 1di 10

Images haven’t loaded yet.

Please exit printing, wait for images to load, and try to


Build responsive React Native views for
print again.

any device and support orientation


change
Tasos Maroudas Follow
Jun 12, 2018 · 7 min read

Image 1: The multiple screen sizes that a responsive design should cover

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:

Image 2: Example of screen responsiveness across Android phones and tablets of di erent screen density

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


Images 3, 4: Pro le scene of Math Warriors Android game

Guidelines on how to use these methods


1. 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 and height: 640DP (these are
the values without taking into account the device's scale factor).

2. Methods widthPercentageToDP and heightPercentageToDP can be


used for any style (CSS) property that accepts DP as value.
Properties with DP values are the ones of type number 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 type number properties used in
your app in order to make your app fully responsive for all screen
sizes.

3. 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.

4. 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:

Image 5: Gif demonstrating how UI adapts its responsiveness to orientation change

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.

marudy/react-native-responsive-screen

react-native-responsive-screen - Make React


Native views responsive for all devices with the…
github.com

What do you think?


What do you think about this solution? Feel free to offer your
perspective and ideas to the comments section below.

If you enjoyed this article, feel free to hit that clap


button 👏 to help others find it.

. . .

About me

About me
Hi, I’m Tasos, a software engineer that loves web and currently works a
lot with React Native and React. I take over project contracts and do
consulting. You can have a look over my portfolio here. If you want to
work with me or just say hi, contact me an email:
tasos.maroudas@codedlines.com

Potrebbero piacerti anche