Different UI/UX on Android and iOS when develop React Native app
Have you ever developed an app on React Native? And when you run it on Android and iOS devices, sometimes you realize they are not exactly the same UI/UX like what you want. It happens because Android and iOS actually have special views and styles on each platform(like Google uses Material design while Apple uses Cupertino).
Today, I will list some basic differences in each platform and show how to deal with it. Now let’s get started.
1. Height of the StatusBar
Android has the status bar with height is about 20, iOS has the same, but it will overlay your screen. So if your Android device has height is 640, actually we have the main content is 620, but on iOS, we’ll get full 640.
Solution: so if you would like to design the header, remember that plus the header 20 units on iOS (and then padding top the content 20 units too, if not, maybe status bar will overlay your content a little bit).
Then the status bar on both platform almost the same
2. StatusBar theme and text color inside
iOS: because status bar on iOS actually overlays your content, so it’s background is transparent, and the background you see is the background of the toolbar.
In some cases, we have a different background color in each screen, then we need to set the text color on iOS (if your toolbar’s background is white, but the default status bar text is white too, then this text can not visible).
Solution: set barStyle
to dark-content or light-content depend on your toolbar’s color
<StatusBar hidden={false} barStyle='dark-content'/>
3. Shadow
iOS gives you shadowColor
(sets the drop shadow color), shadowOffset
(sets the drop shadow offset), shadowOpacity
(sets the drop shadow opacity (multiplied by the color’s alpha component) and shadowRadius
( Sets the drop shadow blur radius) as a style of View.
Android only supports a simple shadow (just a shadow with grey color) by use elevation
as a prop of View.
Solution: implement your own shadow or use the third library like react-native-elevated-view or react-native-shadow
4. Underline color TextInput
Only Android has underline color for TextInput by use underlineColorAndroid
as a prop of it.
Solution: render your own underline and remember to set underlineColorAndroid='rgba(0,0,0,0)'
to hide default underline on Android.
underlineTextInput: {
height: 0.5,
alignSelf: 'stretch',
backgroundColor: 'rgba(38,43,45,0.1)',
},
5. Font
iOS: use script name to refer.
Android: use file name to refer.
So if you use a font has a script name and file name the same, it will fine, but some fonts have a file name different (may be different in capitalization, dash or underline).
Solution: use this lib to read font info, then change the file name like the script name.
6. Push View up when the keyboard’s showing
If you have a screen with many text inputs (like sign-in screen) or a screen with many items (like chat screen), when keyboard’s showing, you want to the keyboard push your content up, so you can see all viewport you’re focusing, but it does not happen the same at all platform.
iOS: keyboard will overlay your content.
Android: keyboard will push up your content (if you’ve already set android:windowSoftInputMode=”adjustResize” at AndroidManifest.xml).
Solution: check out this article https://medium.freecodecamp.org/how-to-make-your-react-native-app-respond-gracefully-when-the-keyboard-pops-up-7442c1535580
Or in my case, I use my own method
First, calculate the keyboard’s height
Then show or hide the padding in render function (on iOS)
{
this.state.isKeyboardShow && Platform.OS === 'ios' ?
<View style={{height: this.state.keyboardHeight}}/> :
null
}
7. Border radius at Text component
Android: work fine.
iOS: you have to wrap it by a View, then set background and border on this wrapper. Or you can set directly to <Text/>
by use overflow:'hidden'
as an attribute in style.
style={{backgroundColor: 'cyan', borderRadius: 10, overflow:'hidden'}}
8. Border radius image (circle avatar)
Example: you have an image with size is 50 x 50
Android: you can set borderRadius equal or larger than 25, the image still is rounded like a circle.
iOS: you have to set exactly borderRadius
25, if larger, image becomes a square or weird shape.
Note: One more thing, some extend borderRadius attributes like: borderBottomLeftRadius
, borderBottomRightRadius
, borderTopLeftRadius
, borderTopRightRadius
won’t work on iOS if you not set overflow:'hidden'
9. Support GIF image
The Image component actually is converted from native view, and the ImageView on Android does not support GIF so Image component is the same too. But on iOS, GIF is displayed fine.
Solution: I recommend use react-native-fast-image to handle things on this case (not recommend use fresco since it seems slow when we have many gif images).
10. Clear TextInput
Let set reference for TextInput like this
ref={component => this.refInput = component}
And this method only works on Android
this.refInput.clear()
To make the text clear on both platforms, we should use
if (Platform.OS === 'ios') {
this.refInput.setNativeProps({text: ' '})
}setTimeout(() => {
this.refInput.setNativeProps({text: ''})
})
11. Text is aligned at center when setting multiline on Android
When you set multiline={true}
notice that this aligns the text to the top on iOS, and centers it on Android like the picture below
Solution: Set textAlignVertical: 'top'
in the style prop to TextInput for the same behavior in both platforms.
12. Open notification when the app’s in background
I’m using OneSignal (version 3.2.7) to handle notification, and when you touch on a notification when the app’s in background, will have a different action in each platform:
iOS: always resume the app.
Android: start new intent or resume the app depend on launchMode
at AndroidManifest.xml
Example: if you don’t set launchMode
for activity, mean it uses default ~ standard, and when you click on notification, the app will start new intent instead of resume => we’ll have multiples instances of the app.
So notice this thing will help you deal with some features (like navigate to a specific screen when touching on a notification).
13. Touches pass through overlay View in Android, but not iOS
Look at this picture, the button with the name GET DATA cannot be press since it was overlain by the view with the yellow background. That’s normal, right?
But the difference at here is when you remove backgroundColor property of this view, then
Android: allow you to press the button.
iOS: still cannot press the button.
Solution: add pointerEvents='box-none'
to overlay View then iOS will works.
14. Deep linking with addEventListener() method
iOS: working fine.
Android: not work.
And notice that life cycle on Android in this case, if you don’t define launchMode
or define it as standard, when the app is in background and the user call this app from deep linking, componentDidMount()
be called again (not happen when value is singleTop, singleTask, singleInstance/ on iOS/ call the app from icon at menu device/ call from multitask)
And take advantage of this feature, we can cheat to make Android work like iOS.
componentDidMount() {
if (Platform.OS === 'android') {
Linking.getInitialURL().then(url => {
// Android always go here when use deep linking
});
} else {
Linking.addEventListener('url', this.handleOpenURL);
}
}
So on Android: every time the app is started from deep linking, componentDidMount()
is called and this method will run, so Android will get the data like the listener on iOS, then they both work the same.
Btw, we even shouldn’t check Platform.OS, because it will cause the bug when app not running at the background on iOS => we can’t receive data, so at that time iOS need the data from getInitialURL()
instead of listener.
Bonus: typing URL Schemes via Chrome not working like Safari:
Chrome does not support you go to the app via typing URL Schemes like Safari, you can try these methods instead:
- Installing Firefox browser on Android and it will work like Safari.
- Create your own simple html web page with tag
<a href=” peopleapp://people/0”>Go</a>
and then accessing this page to click it.
These are different cases I stuck in, I’ll keep updating this list when getting a new issue.
If you guys have any issue or know something more, please inform me then I’ll update the list, it will help our developer easier to make the UI exactly the same on both platforms.
Thanks for reading 💛