Timeless
Published in

Timeless

Adding Custom-Variable Fonts in React Native — Part II

This is the continuation of my previous blog:

Previously in that blog, we would have seen how to slice different font weights from a variable font (e.g. InterV.var.ttf) and add them to Expo App.

Let us look at how to add them in a Bare React Native workflow.

Cover Image by Fayas fs

Creating a react native application through the React Native Command Line Interface.

npx react-native init FontExampleApp

Once the app has been created we can run our application like this.

Let us go ahead and run our application on iOS.

If your app has been successfully launched you can see this screen on your simulator.

An Image of the Apple iPhone Simulator after successfully running our app.

We will be using the expo-font package to link our fonts here too.

If you look at the package documentation it will provide installation steps for both projects

  1. Expo Managed
  2. Bare React Native

So before using Expo modules in our React Native project we will have to install and configure the expo package.

Expo has install-expo-modules a command for getting it done.

npx install-expo-modules@latest

Let us go ahead and run this command in our project.

This command will prompt a question like this:

Expo module's minimum iOS requirement is 13.0. This tool will change your iOS deployment target to 13.0.

I think it's okay. Because it changes the min deployment target. As far as the app runs, I guess.

After the installation is successfully complete, you will have to go ahead and rebuild your iOS App.

Once the rebuild is successful, we can go ahead and add our expo-font package.

expo install expo-font

Additional configuration is required for iOS (and none for Android), you will have to run

npx pod-install

After successfully running the above command let's go ahead and rebuild our app again.

Once the app is built and launched. We will have to load our fonts in a similar fashion we did for the expo app.

Go ahead and create a folder structure like src/assets/fonts .

Add all our previously sliced fonts to this folder.

Image describing the folder structure to add our custom font weight sliced fonts.

Let us copy the code we used in the expo snack, and paste it in our App.js file.

At first, this code will break for two reasons:

  1. We would have used the expo-splash-screen package.

We will install this package now.

npx expo install expo-splash-screen

This package also needs a separate configuration for iOS. Let us run
npx-pod-install and rebuild our project.

2. The path for the font file will be different from the code we copied.

const [fontsLoaded] = useFonts({
'Inter-400-14': require('./src/assets/fonts/Inter-400-14.ttf'),
'Inter-440-14': require('./src/assets/fonts/Inter-440-14.ttf'),
'Inter-460-14': require('./src/assets/fonts/Inter-460-14.ttf'),
'Inter-520-24': require('./src/assets/fonts/Inter-520-24.ttf'),
'Inter-600-30': require('./src/assets/fonts/Inter-600-30.ttf'),
});

As the App.js file resides at the top of our app and our assets are inside the src folder. We have to include them in the path as above.

After that, we can see the output in our iOS Simulator.

That’s all for iOS. 🎉

Let us try to build in android and see if the fonts are working fine.

Initially, my build failed saying I was using an outdated version of Java.

So I straight up headed to the React Native docs to check what is the updated way of running the app on Android Simulator on Mac.

The recommended way of installing the OpenJDK is called Azul Zulu using Homebrew.

Had to run these commands in the terminal to get the latest Azul Zulu JDK.

brew tap homebrew/cask-versions
brew install --cask zulu11

The great thing about Zulu is that

The Zulu OpenJDK distribution offers JDKs for both Intel and M1 Macs. This will make sure your builds are faster on M1 Macs compared to using an Intel-based JDK.

Glad. I am on an M1 Chip Mac. 🎉

Next up we will have to set up our Android Development Environment, install Android Studio, and install Android Studio SDK.

But we don't need the whole development environment, we just need the Emulator to be running while we execute the react native command to run our app.

Thanks to Google.

We have an Android Emulator(still in pre-release, but WORKS!).

If you have it downloaded. And you give the permission to Open the app through settings.

You will have your Android Emulator up and running.

Screenshot of Android Emulator running in MacOS

Now let's run the command to start our application

npx react-native run-android

As everything is set up correctly, you should see our new app running in your Android emulator now.

Let us see the Android and iOS app screenshots side by side now, as we have our all fonts loaded now.

Screenshots of iOS and Android

That's it. 🙌

The final code in App.js is

import {useEffect, useCallback} from 'react';
import {Text, View, StyleSheet} from 'react-native';
import {useFonts} from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import React from 'react';

export default function App() {
const [fontsLoaded] = useFonts({
'Inter-400-14': require('./src/assets/fonts/Inter-400-14.ttf'),
'Inter-440-14': require('./src/assets/fonts/Inter-440-14.ttf'),
'Inter-460-14': require('./src/assets/fonts/Inter-460-14.ttf'),
'Inter-520-24': require('./src/assets/fonts/Inter-520-24.ttf'),
'Inter-600-30': require('./src/assets/fonts/Inter-600-30.ttf'),
});

useEffect(() => {
async function prepare() {
await SplashScreen.preventAutoHideAsync();
}
prepare();
}, []);

const onLayoutRootView = useCallback(async () => {
if (fontsLoaded) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded]);

if (!fontsLoaded) {
return null;
}

return (
<View style={styles.container} onLayout={onLayoutRootView}>
<Text style={styles.Inter_400_14}>Font Weight 400 with opsz 14</Text>
<Text style={styles.Inter_440_14}>Font Weight 440 with opsz 14</Text>
<Text style={styles.Inter_460_14}>Font Weight 460 with opsz 14</Text>
<Text style={styles.Inter_520_24}>Font Weight 520 with opsz 24</Text>
<Text style={styles.Inter_600_30}>Font Weight 600 with opsz 30</Text>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 16,
},
Inter_400_14: {
textAlign: 'center',
fontFamily: 'Inter-400-14',
fontSize: 30,
color: 'black',
},
Inter_440_14: {
textAlign: 'center',
fontFamily: 'Inter-440-14',
fontSize: 30,
color: 'black',
},
Inter_460_14: {
textAlign: 'center',
fontFamily: 'Inter-460-14',
fontSize: 30,
color: 'black',
},
Inter_520_24: {
textAlign: 'center',
fontFamily: 'Inter-520-24',
fontSize: 30,
color: 'black',
},
Inter_600_30: {
textAlign: 'center',
fontFamily: 'Inter-600-30',
fontSize: 30,
color: 'black',
},
});

In the Two-Part Blog series, we successfully sliced different font weights and optical sizing using Slice App and loaded them up in React Native in both workflows, Expo and Bare React Native.

Hope these blogs ease your development process in some way.

Thanks :)

This is Karthik from Timeless

If you find this blog post helpful, tell me in the comments, would love to know your views. Thank you :)

If you find any difficulties or see anything which could be done better, please feel free to add your comments (I really like to read them, maybe something on what my next blog should be? You know. Whatev! ). … :)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Karthik Balasubramanian

Trying to Solve Problems with Code @ timeless.co. Open sourcing the solutions when possible.