So now that the general game logic works, let's focus more on finishing up that styling
and also on adding our own custom fonts and a nice little image on the game over screen because working
with images and working with custom fonts is a typical thing in modern app development of course, you
rarely want to stick to the default system fonts and rarely do you have an app without any images.
So therefore let's get started with custom fonts and in a React Native expo, adding fonts is super trivial.
In your project folder, in the assets folder,
let's create a fonts folder. You can store that anywhere though
but I like to keep it in the assets folder to keep my assets like fonts and images organized.
So here in the fonts folder, I unsurprisingly want to manage my fonts and for that, attached you find
a zip file with two fonts which you can just extract and then drag and drop into here,
that's OpenSans-Bold and OpenSans-Regular,
so these two fonts are attached to this video in a zip file, extracted and drag them into the fonts
folder.
Now with that, these fonts are generally available but to use them, you still need to configure more.
You need to go to your app.js file and basically instruct React Native and expo to load these fonts,
so to use them. For that in the app.js file and I'm using the app.js file because that's the first
file which is loaded or which is executed so to say when the app starts and you want to load your fonts
when the app starts, in there, you need to add an import and that import is that you import everything as
font, though that name here is up to you but typically, you use font here, from expo-font.
So expo-font is a package which gives you font utilities, so utilities that allow you to load fonts
and you import everything from that package and bundle it together in this font object,
that's what we're doing here. Now
to load fonts, I'll add a new function outside of the functional component because this function doesn't
need to be recreated for every component rerender cycle.
Now I'll name it fetch fonts,
the name is up to you
and in this function here,
I will call font.loadAsync.
Now this is a function that or a method on the font package which we're importing here that allows you
to load fonts and what you pass to load async is an object where you tell Expo and therefore React Native
about all the fonts you want to load. You do this by using a key where you pick any name of your choice,
like open-sans and you'll later be able to use these fonts by these names,
so here open sans because my font is called open sans.
So here it's open sans and then you add require,
that's a language feature Javascript offers where you point at the path where this font is stored.
That's a relative path,
so here I point at the assets folder,
the fonts folder and then it's the OpenSans-Bold, not bold but regular.ttf file and now
I'll add a second item here to this object I pass to load async and that could be open-sans-bold.
Now these names are totally up to you and there I want to load the bold version.
So with that, we're telling React Native in the end where our fonts live, where these font files live and
to which names we want to map them and we can later use these names to assign these fonts to text. Now
load async actually returns a promise, which means that this will take a bit longer, not super long but
it will not load these instantaneously and I will return this promise here inside of fetch fonts so
that whenever we call fetch fonts, we can wait for this promise to resolve before we continue. Now where
do we want to fetch our fonts though?
Well we could manually load our fonts here, we could for example call fetch fonts like this and it would
go ahead and fetch our fonts
but the problem is, we would continue rendering and we would eventually render our content and if anywhere
in the content, we use text that tries to use such a font,
if the font hasn't been loaded yet and as I said, it will take only a couple of milliseconds but still
for the first render cycle, the font might not have been loaded, then we would get an error. So loading
our fonts like this is not recommended, it will very likely not work.
Instead there is a special component which you can use, it helps you load your fonts. You import this
component from expo and the name of that component is AppLoading.
Now that's a component which will basically prolong the default loading screen, the splash screen users
see anyways when the app is launching, it will prolong this screen to stay active until a certain task
of your choice is done,
like for example until fetching fonts is done.
So AppLoading it is, in the app component,
we just have to make sure now that we render this component instead of our actual content as long as
we haven't loaded our fonts yet
or as long as we're not done with loading whatever we wanted to load.
Now the cool thing is, we can use state for that and start with an initial value of false because the
state I want to manage here is data loaded or whatever you want to call it and set data loaded.
Now here, I want to check if data loaded is not true, hence the exclamation mark, then I know the data
hasn't been loaded yet and that's the case initially and in this case, I'll not even continue with my
other logic,
instead for this functional component, I'll immediately return the AppLoading component as the content
of the app
basically because I don't want to render any other content if we're still loading our data. Now AppLoading
is a component coming from Expo which takes a start async prop where we point at the operation we want
to start when this is first rendered and that's of course our fetch fonts function.
So here, I'm pointing at fetch fonts, at this function.
Now important, a)
this has to be a function which you pass here and b) it has to be a function that returns a promise because
expo will automatically listen to that promise for you
and when the promise resolves, it will know that the loading is done and it will then call whatever you
pass here to onFinish.
So here, you need to pass a function which then actually sets data loaded to true.
So this function here will be executed for you when this operation is done and for expo to find out
when this is done,
this should return a promise.
So now these two props will work together and we're updating data loaded, this state to be true and therefore
to not render this content but to proceed with executing this code and eventually rendering the
content down there
when fetching our fonts is done and you could do any async operation here but typically, you use AppLoading
to load some assets, like fonts or anything like that,
so assets that should be there when the app starts which you need immediately and typically that are
fonts.
Now you can also add an onError handler here by the way and here, I'll just console log the error object
which we also get here
in cases where loading that fails. Of course, you might not just want to log this but instead, do something
else, show some alternative content in your app,
anything like that. Here I'll just log it because this shouldn't fail,
the fonts are available locally here so that should be loadable without issues.
Now if we save that, our app of course restarts and we see no difference here,
our loading screen also doesn't really take longer as before because that loading is super fast,
it just doesn't happen instantly,
that is why we needed this approach.
But now we loaded the fonts,
how can we now use them?
Well let's say we want to change our start a new game title here to use our font. Now for that,
we need to go to the start game screen which is where this title lives in the end, here, start a new game,
it does have the title style and therefore down in the stylesheet here on title, we can now set font family
to change the font family and set this to open-sans-bold
for example
and of course the identifier you use here has to be an identifier you loaded here.
So here, I have open-sans-bold and open sans,
I can use these two identifiers in my code anywhere in the app when I want to assign a custom font and
that's just what I'm doing here.
Now you see, that has a different font that is bold and by the way, if you're using custom fonts and you
want a bold font, you have to load it with the font family,
you can't set the font weight. React Native supports this but for custom fonts, expo at the moment doesn't
support this,
instead you simply have to use a separate font family which isn't really a problem as you can see.