'React Native - how to set fixed width to individual characters (number, letter, etc)
I am having a problem in a React Native app I'm building. I have a stopwatch and since each number character has a different width, when the time is increased the text begins moving all over the place, as opposed to staying in tact with a fixed width.
For example, if you have a mobile iOS device, open the default clock app that is shipped with it and use your stopwatch. You'll notice that each character in the 00:00:00
series has a fixed width, or at least it seems that way. If one of the 0 turns into a 1, even though 1 is seemingly smaller in width, it still fills up the same amount of space and thus the text does not jump all over the place.
In my React Native app, however, this is not the case. 1 takes up less width than 0 or any other number, so it makes the text jump all over the place and it's really annoying.
Here is a good, working version (notice how on each change of a number, the width of the 'container' that the number is in never changes?) This ensures a smooth transition:
Now take a look at my version, a disaster:
I can't seem to find a solution to this.
I feel like one way to solve this would be to have each character in a separate <Text>
tag with a set width, but I know that would be completely overkill. There must be an easier way to do this.
Any guidance would be appreciated.
Solution 1:[1]
The system font in iOS is San Francisco, which has proportional numbers by default but contains an option for fixed-width (monospaced) numbers. With react-native, you have to use the fontVariant
property on your Text
component's style:
<Text style={{fontVariant: ['tabular-nums']}}>
1,234,567,890.12
</Text>
I had a hard time finding it because the name isn't explicit and not what is typically used. Here's a link to the the Text props on the RN doc: https://facebook.github.io/react-native/docs/text.html#style
Solution 2:[2]
Although the question is tagged for iOS, in case anyone is looking for a generic solution that supports monospace text on both iOS and Android (like I was), then here's an additional resource for you!
Font selection:
react-native-training/react-native-fonts on GitHub has a good list of fonts which are on each platform. As you can see, there is no overlap between the monospace fonts which OP provided in their answer. However, Android has a font called 'monospace' which will work for this use case.
OS Conditional statement
Since react native will throw an error if a font in fontFamily does not exist, we will need to conditionally set the fontFamily based on what's available in the OS. Platform.OS
from react-native can be used to determine the device OS.
Example
// components/TextFixedWidth.js
import React from 'react'
import { Platform, Text } from 'react-native'
export default function TextFixedWidth ({ children }) {
const fontFamily = Platform.OS === 'ios' ? 'Courier' : 'monospace'
return (
<Text style={{fontFamily}}>{ children }</Text>
)
}
Then
// in a render method somewhere in the app
<TextFixedWidth>
Any monospace text you want!
</TextFixedWidth>
I hope this is helpful :)
Solution 3:[3]
Thanks to @ppeterka, I found a super easy solution to this that requires one line of code: use a monospace font.
Here is a list of some available monospace fonts that are shipped with iOS:
- Courier
- Courier-Bold
- Courier-BoldOblique
- Courier-Oblique
- Courier New
- CourierNewPS-BoldItalicMT
- CourierNewPS-BoldMT
- CourierNewPS-ItalicMT
- CourierNewPSMT
- Menlo-Bold
- Menlo-BoldItalic
- Menlo-Italic
- Menlo-Regular
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Ethan O. |
Solution 2 | |
Solution 3 |