Don’t hesitate to support the iPad in React Native 🍃

MJ Studio
MJ Studio
Published in
10 min readMar 21, 2020

Everything to consider when developing a UI with React Native related to the unit, value.

So many tablets! 👅

Construct UI in mobile development 🎋

I am a React Native beginner and was an Android/iOS native developer. When I developed iOS, the one thing makes me comfortable than Android was the fact that there are just a few iOS devices in the world(Thanks for Apple). If you have been published your Android application in Play Store, you may be surprised there are over 10 thousand Android devices in the world!

To be a pro-minded developer, we can’t tolerance any user complaints about layout in our application. I think constructing UI layout is a kind of most difficult part of the application development process. Just putting View or Button or Image to our screens with GUI editor or in the code are not difficult ones, but if screens in the application of your company have complex UI layout or many translations or long, undetermined texts, then supporting whole devices in the world is more difficult.😧

If you experienced Android or iOS native development, then you already know about ConstraintLayout in Android or Auto Layout System in UIKit. React Native adopts the flex-box system for construct UI. The three things have their pros & cons and trade-off. But basically, they do the same thing. We can adjust the width & height of views with constants or percentage with parent or screen. Furthermore, there are built-in technics for supporting devices with similar font size or view dimensions with units 📏. Yes, you may already know about that. They are PT and DP

PT(iOS) & DP(Android) 🍃

There are units in mobile development like DP, SP, and PT. Their concepts have been created because of devices' diversity. The basic unit in the device screen is PX(pixel). For example, if you visit iOS device screen homepage, then you can see the native resolution means pixel. And you can see also UIKit Size also next to the pixel.

https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html

If you see the above table carefully, with Points(PT), you notice that the size difference in devices is not greater than Pixels(PX) except iPad tablets. The display technology has been developed and customers have wanted to watch their favorite movie or Youtube videos with high-resolution screens. Therefore, the number of pixels on the screen is absolutely larger than in the past. Then, how can developers(we!) support the whole size of devices at once with only one storyboard or XML? For the best UI/UX, we can develop screens for each device type(cell phone, tablet). But that is so time-consuming work and doesn’t match our case(developers in the team are only you!). At this, DP and PT rescue us 🎉.

The iOS devices have their scale factor. In the above table, iPhone X has 1125 x 2436 pixels in its retina device. Also, we can see their size in PT world is just 375 x 812. Did you see the native scale factor also? Then you can easily guess that “Oh, 375(width in point) multiply with 3.0(native scale factor) is 1125(width in pixel)!” Yes, this is how the point unit works in the iOS world. The basic unit of iOS is PT. Each native scale factor of the device refers to the scale value used to divide the actual pixel size to get the point size (relative size)

https://blog.fluidui.com/designing-for-mobile-101-pixels-points-and-resolutions/

The default unit in React Native world also be the PT if we launch our application with the iOS device!

Dimensions.get('window').width === 375 // launched with iPhoneX

So we can freely use const dimension = 40; for width, height, margin, padding, etc… Then, the iOS devices automatically will adjust 40 with native scale factor In iPhone X, the 40 PT will be 120 PX on the actual screen. We can also prepare 3 different sizes for the same image for each device. This is why the image resources in iOS managed with postfix like 2x, 3x

In the Android world, the stated concept is not different so much. I described iOS more detail than I thought so, I will mention Android briefly. Android separated their devices in 5 screen size types. mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi are that(there is others like ldpi, but not important).

https://developer.android.com/training/multiscreen/screendensities

DPI(PPI) is short for dot(pixel)-per-inch. Dot means 1 pixel. We can determine what range is a match for Android devices using the DPI concept. For example, Samsung Galaxy S10 has screen resolution specs like the following.

https://yesviz.com/devices/s10/

PIXELS PER INCH of Galaxy S10(550) is in the range of 480~640. So we can decide this device isxxxhdpi. In the native Android development, we use unit DP(SP for text). DP is also a relative unit about the device. If we use 40dp for dimension in development, then in the actual device, 40dp will be 160pixels 😃

The default unit in React Native world also be the DP if we launch our application with the Android device!

We explored the techniques for supporting device screen size diversity in the mobile development world. The relative units in devices of each platform automatically will be scaled. Is our short journey end here? Never ❌ You will soon see a shocking picture.

The Real-World Problem 🙉

The trick in using relative value.

With PT and DP, I can make our layout like this.

<Container>
<
View
style={{
width: 100,
height: 100,
marginLeft: 200,
marginTop: 200,
backgroundColor: 'black',
}}
/>
<
Text style={{ marginLeft: 100, marginTop: 300, fontSize: 14 }}>
MarginLeft 300, MarginTop 500
</Text>
</
Container>

Will be result in..

Text in iPhone SE is even out of bound!

😧I admit that I assumed an absurd situation. You can ask “Is it used DP or PT really??”. Yes, in React Native, just number in layout means PT in iOS and DP in Android undoubtedly.

Then, what makes the situation like above? I think this is the most tricky part for understanding layout in mobile development to developers and designers also. The newbies in client developers believe 100% that with the relative unit in layout configuration, they can support whole devices in the world! I was too :(

But, in the real world, there is a trick. The relative units don’t resolve all problems. For example, iPhone X has 375 point width and iPhone SE has 320. What if using a View with a width of 320?

iPhone X vs iPhone SE

The black view filled all width in iPhone SE but not iPhone X. If we think more carefully about this, we can discover what is the problem. 320 PT is will be 960 in iPhone X(native scale factor = 3) and 640 in iPhone SE(native scale factor = 2). But the actual width of the iPhone X is 1125 pixels! That is a trap.

Generally, in the above case, using a width percentage is a more helpful and simple way. Or, we can use value with ratio using screen width or screen height for dimensions. But if we using screenHeight * 0.1 to the height of each view, the code is less readable and be easy to confuse. Also, in the font size problem, imagine we have to use it as the following syntax.

<Text style={{ fontSize: screenHeight * 0.02, fontWeight: 'bold' }}>

It is a terrible one.

Device Configuration

Android and iOS devices have features like display zoom and adjust font scaling. If we turn on these features in device settings, then the contents and font size of our app(whole app) is changed.

Setting font scaling in device settings doesn’t affect iOS but Android does. In iOS, that is an opt-in feature, but opt-out in Android.

We can opt-out font scaling option in android with allowFontScaling props in <Text> .

<Text
allowFontScaling={false}
style={{ fontSize: 16, color: 'blue' }}
>
{
item.name}
</
Text>

I set my same Android emulators only differently with font scaling to the default and largest. Let me show the change of application look depend on whether allowFontScaling is set or not.

This is an FlatList example and common mistake.

renderItem={({ item }): ReactElement => (
<
View
style={{
width: '100%',
height: 60,
borderBottomWidth: 1,
borderBottomColor: 'black',
}}
>
<
Text style={{ fontSize: 24, fontWeight: 'bold' }}>
{
item.name}
</
Text>
<
Text style={{ fontSize: 16, color: 'blue' }}>{item.name}</Text>
</
View>
)}

The above codes look like they have no problem. But…

Text Size Large vs Text Size Default in the same devices when allowFontScaling is true(default)

Because we set our item height of FlatList to 60 fixed, the scaled text-overflow boundary of item View 💥Let’s add allowFontScaling props to false .

...
<
Text
allowFontScaling={false}
style={{ fontSize: 24, fontWeight: 'bold' }}
>
{
item.name}
</
Text>
<
Text
allowFontScaling={false}
style={{ fontSize: 16, color: 'blue' }}
>
{
item.name}
</
Text>
...
Text Size Large vs Text Size Default in the same devices when allowFontScaling is false(manual set)

Generally, I set allowFontScaling to false to prevent the above situation.
You can ask like “Why do you disable allowFontScaling? That prop is useful to support many devices using automatically adjusting font size.”

Nope! Font sizing is not related to the size of the device screen. This is a selectable setting for older people. You should focus on how to adjust the content and font size according to the screen size of the device without any interference like the settings mentioned.

Setting the display zoom is more problematic in the Android world. It is hard to disable than the font scale setting. In iOS, display zoom is not a problem because only large-screen device support display zoom so they have maximum zoom boundary of size.

Let’s suppose we disabled the font scale setting in Android and made different with display size setting. And let me show one more terrible situation example.

device size setting small vs device size setting largest

The display size options change screen width and height also. So, our item View having 60 height is wider in device set device size largest than small.

How can we prevent the above situation? All of this has made it difficult to organize UI layouts in development.

Simple but Mathematically Solution 📐

First, I hate math 😞. But I made a simple util function and Component with simple arithmetic operations.

The relative units using scale factor for device diversity. I just add one scale factor to that process. Suppose your viewport in design guideline(Zeplin, XD, Pigma, etc…) is 375 x height.

Then you can refer dimension in design guideline tools with hovering or press component. We used that value to dimensions like width, height or margin. But what if we could adjust the unit once more to fit the viewport of the design guidelines?

I made a simple util function.

dimenRatio: I calculated a scale factor between the length of screen width and design guideline viewport width.

dimenScale: I just clamped value to value match in range.

fontScale: also clamped value. the difference with dimenScale is scale value is squared when the value has to be smaller.

I also set defaultFontSize for custom Text Component.

I can also use this scale factor with multiply syntax in javascript like the following.

<Text style={{ fontSize: 16 * fontScale }}>{item.name}</Text>

But I didn’t. I used the Javascript monkey-patch extension(augmentation) of native Number type.

<Text style={{ fontSize: (16).fontScaled() }}>{item.name}</Text>

I also made a simple Text Component

I used allowFontScaling options for allow applying my custom scale factor instead of native device setting scale factor

<ScaledText style={{ fontSize: 16 }}>{item.name}</ScaledText>

You can use customFontScale also.

<ScaledText customFontScale={isTablet ? 2 : undefined}>My Text</ScaledText>

I packed these features into a simple library.

But, the purpose of this article is not introducing my package but introducing my problem solve way, and basic concept and commonly misunderstood concepts in construct layout in mobile development.

Here is a result of our company application.

Conclusion

There are so many methods for supporting the whole device's layout in mobile development. But, if you don’t know what configuration can be a problem in the future during development, that problem will be a nightmare.

Thank you for enjoying my article. Any feedback or contributing is welcome! 🎉

--

--