Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom fonts support The Android Way #24595

Closed
wants to merge 13 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

package com.facebook.react.uiapp;

import android.app.Activity;
import android.os.Bundle;

import com.facebook.react.ReactActivity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.react.views.text.ReactFontManager;

import java.util.Arrays;
import java.util.List;

import javax.annotation.Nullable;

public class RNTesterApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
Expand All @@ -29,7 +28,7 @@ public String getJSMainModuleName() {
}

@Override
public @Nullable String getBundleAssetName() {
public String getBundleAssetName() {
return "RNTesterApp.android.bundle";
}

Expand All @@ -46,6 +45,12 @@ public List<ReactPackage> getPackages() {
}
};

@Override
public void onCreate() {
ReactFontManager.getInstance().addCustomFont(this, "Srisakdi", R.font.srisakdi);
super.onCreate();
}

@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
Expand Down
5 changes: 5 additions & 0 deletions RNTester/android/app/src/main/res/font/srisakdi.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
<font app:fontStyle="normal" app:fontWeight="400" app:font="@font/srisakdi_regular"/>
<font app:fontStyle="normal" app:fontWeight="700" app:font="@font/srisakdi_bold" />
</font-family>
Binary file not shown.
Binary file not shown.
8 changes: 8 additions & 0 deletions RNTester/js/TextExample.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,14 @@ class TextExample extends React.Component<{}> {
<Text style={{fontFamily: 'notoserif', fontStyle: 'italic'}}>
NotoSerif Italic (Missing Font file)
</Text>
<Text style={{fontFamily: 'Srisakdi'}}>Srisakdi Regular</Text>
<Text
style={{
fontFamily: 'Srisakdi',
fontWeight: 'bold',
}}>
Srisakdi Bold
</Text>
</View>
</View>
</RNTesterBlock>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@

package com.facebook.react.views.text;

import javax.annotation.Nullable;

import android.content.res.AssetManager;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {

/**
Expand All @@ -39,7 +40,7 @@ public CustomStyleSpan(
int fontStyle,
int fontWeight,
@Nullable String fontFamily,
AssetManager assetManager) {
@NonNull AssetManager assetManager) {
mStyle = fontStyle;
mWeight = fontWeight;
mFontFamily = fontFamily;
Expand All @@ -52,7 +53,7 @@ public void updateDrawState(TextPaint ds) {
}

@Override
public void updateMeasureState(TextPaint paint) {
public void updateMeasureState(@NonNull TextPaint paint) {
apply(paint, mStyle, mWeight, mFontFamily, mAssetManager);
}

Expand Down Expand Up @@ -116,5 +117,4 @@ private static void apply(
}
paint.setSubpixelText(true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@

package com.facebook.react.views.text;

import javax.annotation.Nullable;

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Typeface;
import android.util.SparseArray;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.res.ResourcesCompat;

/**
* Class responsible to load and cache Typeface objects. It will first try to load typefaces inside
* the assets/fonts folder and if it doesn't find the right Typeface in that folder will fall back
Expand All @@ -36,10 +39,12 @@ public class ReactFontManager {

private static ReactFontManager sReactFontManagerInstance;

private Map<String, FontFamily> mFontCache;
final private Map<String, FontFamily> mFontCache;
final private Map<String, Typeface> mCustomTypefaceCache;

private ReactFontManager() {
mFontCache = new HashMap<>();
mCustomTypefaceCache = new HashMap<>();
}

public static ReactFontManager getInstance() {
Expand All @@ -49,8 +54,7 @@ public static ReactFontManager getInstance() {
return sReactFontManagerInstance;
}

public
@Nullable Typeface getTypeface(
public @Nullable Typeface getTypeface(
String fontFamilyName,
int style,
AssetManager assetManager) {
Expand All @@ -60,6 +64,13 @@ public static ReactFontManager getInstance() {
mFontCache.put(fontFamilyName, fontFamily);
}

if(mCustomTypefaceCache.containsKey(fontFamilyName)) {
return Typeface.create(
mCustomTypefaceCache.get(fontFamilyName),
style
);
}

Typeface typeface = fontFamily.getTypeface(style);
if (typeface == null) {
typeface = createTypeface(fontFamilyName, style, assetManager);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there value caching invidual styled Typeface (normal/italic/bold/boldItalic) instances here like it's done for fonts in assets? Besides that all LGTM.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to use styles or weights you have to define fonts using XML.

Expand All @@ -71,6 +82,20 @@ public static ReactFontManager getInstance() {
return typeface;
}

/*
* This method allows you to load custom fonts from res/font folder as provided font family name.
* Fonts may be one of .ttf, .otf or XML (https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml).
* To support multiple font styles or weights, you must provide a font in XML format.
*
* ReactFontManager.getInstance().addCustomFont(this, "Srisakdi", R.font.srisakdi);
*/
public void addCustomFont(@NonNull Context context, @NonNull String fontFamily, int fontId) {
Typeface font = ResourcesCompat.getFont(context, fontId);
if (font != null) {
mCustomTypefaceCache.put(fontFamily, font);
}
}

/**
* Add additional font family, or replace the exist one in the font memory cache.
* @param style
Expand Down