Creating responsive apps is not something that widely discussed in React Native and most tutorials or documentation don't mention it. I remember assuming, in a moment of insanity, the sizing would "just work", and we would not need to think much of it.
This is not true, sadly. And it's good to be aware of some of the ways we can get our designs to look nice on all target screens.
This post is not intended to get too into the details, rather it is intended to just speak about general concepts and tools so that you have a broad overview of how you might go about setting up your projects
A combination of tools and concepts to understand, will give you the best results:
Before thinking about resizing elements. It's important to know that React Native uses a coordinate space
made up of units that don't necessarily map 1:1 with pixels. This is because some screens have higher resolution than others (more pixels fit on the screen, which in turns provide more detail), while the actual screen size of the device may be the same dimensions as screen sizes of a lower resolution. Since a screen can have such a difference in how many pixels are drawn on it, it doesn't make much sense to have a coordinate space that uses pixels, it would be very difficult to place items on a screen with that large of a variation of units.
With density independent pixels (dp), React Native defines a coordinate space separate from the resolution of the device. This makes it much more simpler to place items. An item of 300(dp) in width, will generally cover the same amount of space no matter the screen size, even if the resolution of the devices varies. It is predictable, and easy to guess roughly where elements are placed and sized.
While the assistance of density independent pixels helps you have a consistent size between screens, it doesn't really assist in how to fill up extra space on a component if you go from a phone screen size to a tablet screen size, for example. If you set a width of 300 on a phone, viewing the component on a tablet will show extra space because the tablet is wider. This is where you may want your component to stretch to whatever the device width is, using Flexbox, instead of using fixed numbers. Flexbox also gives you some very useful alignment features for child components, where you may space these items evenly no matter the screen width. One thing to note is that in React Native, the Flexbox implementation is not the same as on the web. There are limitations, but you still should have what you need to tackle most layout challenges.
If Flexbox can't handle a certain layout, or if for some reason, you need more fine grained control of positioning, you can try placing items on screen depending on the screen width or height. To do this you will use the Dimensions
object from React Native
import {Dimensions, View, Text} from 'react-native';
const {width, height} = Dimensions.get('window');
...
render() {
return <View>
<View><Text style={{position: 'absolute', top: 0, left: width * .8 }}>Some text</Text></View>
</View>
}
The above example would place your text field at 80% the width of your device. The text will always be at 80% of the screen width, no matter the size of the screen.
Unfortunately, font sizes will not magically resize with a screen size change, although it should be noted that on Android you have some control on font size by editing your device's font size settings. For all other purposes you can use Dimensions
to determine a proper font size, depending on the screen width.
import {Dimensions, View, Text} from 'react-native';
const {width, height} = Dimensions.get('window');
...
render() {
return <View style={{flex: 1}}>
<Text style={{fontSize: width * 0.3 }}>Text 1</Text>
</View>
}
You may use percentages to size items, which are helpful in some situations as well.
render() {
return <View style={{flex: 1}}>
<View style={{width: '50%'}}><Text>Text 1</Text></View>
<View style={{width: '50%'}}><Text>Text 2</Text></View>
</View>
}
The above will size the two views to 50% of the parent view's width. In this case the parent view has a flex of 1 which will automatically stretch to fit the device width. The child views will always be 50% of the device's width.
PixelRatio is handy for sizing images and fonts. Yes, font sizing will not magically look great on all screen sizes either :( . Images which haven't been properly sized for your screen won't look great, so make sure to use PixelRatio for that too.
Images
import { Component } from "react";
import { Image, PixelRatio } from "react-native";
export default class MyUserThumbnail extends Component {
render() {
const size = PixelRatio.getPixelSizeForLayoutSize(20);
return (
<View>
<Image
source={{ uri: "http://some-uri.com/uri", width: size, height: size }}
style={{ width: 20, height: 20 }}
/>
;
</View>
);
}
}
To get images to look properly on high dpi devices, you actually have to multiply their size by the dpi value. The getPixelSizeForLayoutSize
method simply does this and returns the multiplied values back. This ensures your images look crisp.
I hope this has helped you better understand your options when setting up your project for multiple screens.