Different UI/UX on Android and iOS when develop React Native app

Duy Tran
7 min readNov 4, 2018

--

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

Status bar on iOS
Status bar on Android

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

Text color mixed with background color on iOS

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'}}
Add overflow property to Text component

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.

Weird shape when you set larger than size/2

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.

Should set singTop at activity to resume app like iOS does

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 💛

--

--