mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-03-06 22:37:14 +08:00
add support for native/downloadable fonts (#23865)
Summary: Android API 26 and Android Support Library 26 added support for font resource type and native/downloadable fonts. It allows apps to easily download fonts from online providers, but also use of various font weights other than normal and bold, like medium. So it deprecated APIs for asset fonts, and should be removed in the future. Advantages: - Just copy font files in res/font and use it specifying filename (without extension) in fontFamily - Define custom font-family using XML file (in res/font) and font files, it may have many weights and styles. See PR for example. - Define configuration to download fonts from online font providers, and use it. See https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml and https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts [Android] [Changed] - add support for custom/downloadable fonts Pull Request resolved: https://github.com/facebook/react-native/pull/23865 Differential Revision: D14506542 Pulled By: hramos fbshipit-source-id: 67ba3148fb4b548cdbc779213cf6c1b2c3baffd2
This commit is contained in:
committed by
Facebook Github Bot
parent
d338a60cbe
commit
f01c4e2a14
5
RNTester/android/app/src/main/res/font/srisakdi.xml
Normal file
5
RNTester/android/app/src/main/res/font/srisakdi.xml
Normal file
@@ -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>
|
||||
BIN
RNTester/android/app/src/main/res/font/srisakdi_bold.ttf
Executable file
BIN
RNTester/android/app/src/main/res/font/srisakdi_bold.ttf
Executable file
Binary file not shown.
BIN
RNTester/android/app/src/main/res/font/srisakdi_regular.ttf
Executable file
BIN
RNTester/android/app/src/main/res/font/srisakdi_regular.ttf
Executable file
Binary file not shown.
@@ -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>
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
|
||||
package com.facebook.react.views.text;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
@@ -29,31 +31,30 @@ public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
|
||||
* Fonts are retrieved and cached using the {@link ReactFontManager}
|
||||
*/
|
||||
|
||||
private final AssetManager mAssetManager;
|
||||
|
||||
private final int mStyle;
|
||||
private final int mWeight;
|
||||
private final @Nullable String mFontFamily;
|
||||
private final Context mContext;
|
||||
|
||||
public CustomStyleSpan(
|
||||
int fontStyle,
|
||||
int fontWeight,
|
||||
@Nullable String fontFamily,
|
||||
AssetManager assetManager) {
|
||||
@Nonnull Context context) {
|
||||
mStyle = fontStyle;
|
||||
mWeight = fontWeight;
|
||||
mFontFamily = fontFamily;
|
||||
mAssetManager = assetManager;
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
apply(ds, mStyle, mWeight, mFontFamily, mAssetManager);
|
||||
apply(ds, mStyle, mWeight, mFontFamily, mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMeasureState(TextPaint paint) {
|
||||
apply(paint, mStyle, mWeight, mFontFamily, mAssetManager);
|
||||
public void updateMeasureState(@Nonnull TextPaint paint) {
|
||||
apply(paint, mStyle, mWeight, mFontFamily, mContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +83,7 @@ public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
|
||||
int style,
|
||||
int weight,
|
||||
@Nullable String family,
|
||||
AssetManager assetManager) {
|
||||
Context context) {
|
||||
int oldStyle;
|
||||
Typeface typeface = paint.getTypeface();
|
||||
if (typeface == null) {
|
||||
@@ -103,7 +104,7 @@ public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
|
||||
}
|
||||
|
||||
if (family != null) {
|
||||
typeface = ReactFontManager.getInstance().getTypeface(family, want, assetManager);
|
||||
typeface = ReactFontManager.getInstance().getTypeface(family, want, context);
|
||||
} else if (typeface != null) {
|
||||
// TODO(t9055065): Fix custom fonts getting applied to text children with different style
|
||||
typeface = Typeface.create(typeface, want);
|
||||
@@ -116,5 +117,4 @@ public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
|
||||
}
|
||||
paint.setSubpixelText(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
textShadowNode.mFontStyle,
|
||||
textShadowNode.mFontWeight,
|
||||
textShadowNode.mFontFamily,
|
||||
textShadowNode.getThemedContext().getAssets())));
|
||||
textShadowNode.getThemedContext())));
|
||||
}
|
||||
if (textShadowNode.mIsUnderlineTextDecorationSet) {
|
||||
ops.add(new SetSpanOperation(start, end, new ReactUnderlineSpan()));
|
||||
|
||||
@@ -12,10 +12,14 @@ 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.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
|
||||
@@ -37,9 +41,11 @@ public class ReactFontManager {
|
||||
private static ReactFontManager sReactFontManagerInstance;
|
||||
|
||||
private Map<String, FontFamily> mFontCache;
|
||||
private Map<String, Typeface> mTypeCache;
|
||||
|
||||
private ReactFontManager() {
|
||||
mFontCache = new HashMap<>();
|
||||
mTypeCache = new HashMap<>();
|
||||
}
|
||||
|
||||
public static ReactFontManager getInstance() {
|
||||
@@ -49,8 +55,7 @@ public class ReactFontManager {
|
||||
return sReactFontManagerInstance;
|
||||
}
|
||||
|
||||
public
|
||||
@Nullable Typeface getTypeface(
|
||||
private @Nullable Typeface getTypeface(
|
||||
String fontFamilyName,
|
||||
int style,
|
||||
AssetManager assetManager) {
|
||||
@@ -71,6 +76,33 @@ public class ReactFontManager {
|
||||
return typeface;
|
||||
}
|
||||
|
||||
public @Nullable Typeface getTypeface(
|
||||
String fontFamilyName,
|
||||
int style,
|
||||
Context context) {
|
||||
Typeface font = mTypeCache.get(fontFamilyName);
|
||||
|
||||
if (font != null) {
|
||||
return Typeface.create(
|
||||
font,
|
||||
style
|
||||
);
|
||||
}
|
||||
|
||||
int fontId = context.getResources().getIdentifier(fontFamilyName, "font", context.getPackageName());
|
||||
if (fontId != 0) {
|
||||
font = ResourcesCompat.getFont(context, fontId);
|
||||
if (font != null) {
|
||||
mTypeCache.put(fontFamilyName, font);
|
||||
return Typeface.create(
|
||||
font,
|
||||
style
|
||||
);
|
||||
}
|
||||
}
|
||||
return getTypeface(fontFamilyName, style, context.getAssets());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional font family, or replace the exist one in the font memory cache.
|
||||
* @param style
|
||||
|
||||
@@ -97,7 +97,7 @@ public class TextLayoutManager {
|
||||
textAttributes.mFontStyle,
|
||||
textAttributes.mFontWeight,
|
||||
textAttributes.mFontFamily,
|
||||
context.getAssets())));
|
||||
context)));
|
||||
}
|
||||
if (textAttributes.mIsUnderlineTextDecorationSet) {
|
||||
ops.add(new SetSpanOperation(start, end, new ReactUnderlineSpan()));
|
||||
|
||||
@@ -221,7 +221,7 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
|
||||
Typeface newTypeface = ReactFontManager.getInstance().getTypeface(
|
||||
fontFamily,
|
||||
style,
|
||||
view.getContext().getAssets());
|
||||
view.getContext());
|
||||
view.setTypeface(newTypeface);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user