Skip to content

Commit fd6386a

Browse files
dulmandakhfacebook-github-bot
authored andcommitted
custom fonts support The Android Way (#24595)
Summary: In #23865, RN introduced support for custom fonts the Android Way. But it introduced performance regression because it'll lookup for a font using getIdentifier() every time fontFamily changed. This PR fixes regression by requiring custom fonts to be listed in **fonts** array, and populating **mTypeCache** at first use using the list. [Android] [Changed] - Require custom fonts to list in **fonts** array. Fixes performance regression. Pull Request resolved: #24595 Reviewed By: mdvacca Differential Revision: D15184590 Pulled By: fkgozali fbshipit-source-id: e3feb2396609583ebc95101130186a1f5af931da
1 parent 661b3b6 commit fd6386a

File tree

8 files changed

+56
-14
lines changed

8 files changed

+56
-14
lines changed

RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.java

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
package com.facebook.react.uiapp;
1010

11-
import android.app.Activity;
1211
import android.os.Bundle;
1312

1413
import com.facebook.react.ReactActivity;

RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@
1515
import com.facebook.react.ReactNativeHost;
1616
import com.facebook.react.ReactPackage;
1717
import com.facebook.react.shell.MainReactPackage;
18+
import com.facebook.react.views.text.ReactFontManager;
1819

1920
import java.util.Arrays;
2021
import java.util.List;
2122

22-
import javax.annotation.Nullable;
23-
2423
public class RNTesterApplication extends Application implements ReactApplication {
2524
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
2625
@Override
@@ -29,7 +28,7 @@ public String getJSMainModuleName() {
2928
}
3029

3130
@Override
32-
public @Nullable String getBundleAssetName() {
31+
public String getBundleAssetName() {
3332
return "RNTesterApp.android.bundle";
3433
}
3534

@@ -46,6 +45,12 @@ public List<ReactPackage> getPackages() {
4645
}
4746
};
4847

48+
@Override
49+
public void onCreate() {
50+
ReactFontManager.getInstance().addCustomFont(this, "Srisakdi", R.font.srisakdi);
51+
super.onCreate();
52+
}
53+
4954
@Override
5055
public ReactNativeHost getReactNativeHost() {
5156
return mReactNativeHost;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
3+
<font app:fontStyle="normal" app:fontWeight="400" app:font="@font/srisakdi_regular"/>
4+
<font app:fontStyle="normal" app:fontWeight="700" app:font="@font/srisakdi_bold" />
5+
</font-family>
Binary file not shown.
Binary file not shown.

RNTester/js/TextExample.android.js

+8
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,14 @@ class TextExample extends React.Component<{}> {
182182
<Text style={{fontFamily: 'notoserif', fontStyle: 'italic'}}>
183183
NotoSerif Italic (Missing Font file)
184184
</Text>
185+
<Text style={{fontFamily: 'Srisakdi'}}>Srisakdi Regular</Text>
186+
<Text
187+
style={{
188+
fontFamily: 'Srisakdi',
189+
fontWeight: 'bold',
190+
}}>
191+
Srisakdi Bold
192+
</Text>
185193
</View>
186194
</View>
187195
</RNTesterBlock>

ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77

88
package com.facebook.react.views.text;
99

10-
import javax.annotation.Nullable;
11-
1210
import android.content.res.AssetManager;
1311
import android.graphics.Paint;
1412
import android.graphics.Typeface;
1513
import android.text.TextPaint;
1614
import android.text.style.MetricAffectingSpan;
1715

16+
import androidx.annotation.NonNull;
17+
import androidx.annotation.Nullable;
18+
1819
public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
1920

2021
/**
@@ -39,7 +40,7 @@ public CustomStyleSpan(
3940
int fontStyle,
4041
int fontWeight,
4142
@Nullable String fontFamily,
42-
AssetManager assetManager) {
43+
@NonNull AssetManager assetManager) {
4344
mStyle = fontStyle;
4445
mWeight = fontWeight;
4546
mFontFamily = fontFamily;
@@ -52,7 +53,7 @@ public void updateDrawState(TextPaint ds) {
5253
}
5354

5455
@Override
55-
public void updateMeasureState(TextPaint paint) {
56+
public void updateMeasureState(@NonNull TextPaint paint) {
5657
apply(paint, mStyle, mWeight, mFontFamily, mAssetManager);
5758
}
5859

@@ -116,5 +117,4 @@ private static void apply(
116117
}
117118
paint.setSubpixelText(true);
118119
}
119-
120120
}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactFontManager.java

+30-5
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@
77

88
package com.facebook.react.views.text;
99

10-
import javax.annotation.Nullable;
11-
1210
import java.util.HashMap;
1311
import java.util.Map;
1412

13+
import android.content.Context;
1514
import android.content.res.AssetManager;
1615
import android.graphics.Typeface;
1716
import android.util.SparseArray;
1817

18+
import androidx.annotation.NonNull;
19+
import androidx.annotation.Nullable;
20+
import androidx.core.content.res.ResourcesCompat;
21+
1922
/**
2023
* Class responsible to load and cache Typeface objects. It will first try to load typefaces inside
2124
* the assets/fonts folder and if it doesn't find the right Typeface in that folder will fall back
@@ -36,10 +39,12 @@ public class ReactFontManager {
3639

3740
private static ReactFontManager sReactFontManagerInstance;
3841

39-
private Map<String, FontFamily> mFontCache;
42+
final private Map<String, FontFamily> mFontCache;
43+
final private Map<String, Typeface> mCustomTypefaceCache;
4044

4145
private ReactFontManager() {
4246
mFontCache = new HashMap<>();
47+
mCustomTypefaceCache = new HashMap<>();
4348
}
4449

4550
public static ReactFontManager getInstance() {
@@ -49,8 +54,7 @@ public static ReactFontManager getInstance() {
4954
return sReactFontManagerInstance;
5055
}
5156

52-
public
53-
@Nullable Typeface getTypeface(
57+
public @Nullable Typeface getTypeface(
5458
String fontFamilyName,
5559
int style,
5660
AssetManager assetManager) {
@@ -60,6 +64,13 @@ public static ReactFontManager getInstance() {
6064
mFontCache.put(fontFamilyName, fontFamily);
6165
}
6266

67+
if(mCustomTypefaceCache.containsKey(fontFamilyName)) {
68+
return Typeface.create(
69+
mCustomTypefaceCache.get(fontFamilyName),
70+
style
71+
);
72+
}
73+
6374
Typeface typeface = fontFamily.getTypeface(style);
6475
if (typeface == null) {
6576
typeface = createTypeface(fontFamilyName, style, assetManager);
@@ -71,6 +82,20 @@ public static ReactFontManager getInstance() {
7182
return typeface;
7283
}
7384

85+
/*
86+
* This method allows you to load custom fonts from res/font folder as provided font family name.
87+
* Fonts may be one of .ttf, .otf or XML (https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml).
88+
* To support multiple font styles or weights, you must provide a font in XML format.
89+
*
90+
* ReactFontManager.getInstance().addCustomFont(this, "Srisakdi", R.font.srisakdi);
91+
*/
92+
public void addCustomFont(@NonNull Context context, @NonNull String fontFamily, int fontId) {
93+
Typeface font = ResourcesCompat.getFont(context, fontId);
94+
if (font != null) {
95+
mCustomTypefaceCache.put(fontFamily, font);
96+
}
97+
}
98+
7499
/**
75100
* Add additional font family, or replace the exist one in the font memory cache.
76101
* @param style

0 commit comments

Comments
 (0)