Skip to content

Commit

Permalink
custom fontWeight numeric values for Text on Android (#25341)
Browse files Browse the repository at this point in the history
Summary:
I found that on Android we only support 2 fontWeight options, either **normal** or **bold**, even developer can set any numeric value. But iOS supports all possible numeric values. This PR tries to add support for all possible numeric values on Android, even if it's supported only on Android P(28) and above.

This change might break texts where fontWeight use improperly, because this PR removes conversion of values above 500 to BOLD and below 500 to normal.

FYI, also moved **mCustomTypefaceCache** usage up because it was working after unnecessary mFontCache usage.

## Changelog

[Android] [Changed] - add custom font weight support to Text component on Android, only on P(API 28) and above versions.
Pull Request resolved: #25341

Test Plan: RNTester app's Text examples will show Rubik Regular, Rubik Light, Rubik Bold, Rubik Medium and Rubik Medium Italic texts in corresponding font family, style and weights.

Differential Revision: D15956350

Pulled By: mdvacca

fbshipit-source-id: 61079d953c65fb34ab4497d44c22317912a5a616
  • Loading branch information
dulmandakh authored and facebook-github-bot committed Jun 22, 2019
1 parent 9ed6dc7 commit 3915c0f
Show file tree
Hide file tree
Showing 14 changed files with 70 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public List<ReactPackage> getPackages() {

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

Expand Down
8 changes: 8 additions & 0 deletions RNTester/android/app/src/main/res/font/rubik.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
<font app:fontStyle="normal" app:fontWeight="300" app:font="@font/rubik_light"/>
<font app:fontStyle="normal" app:fontWeight="400" app:font="@font/rubik_regular"/>
<font app:fontStyle="normal" app:fontWeight="500" app:font="@font/rubik_medium" />
<font app:fontStyle="normal" app:fontWeight="700" app:font="@font/rubik_bold" />
<font app:fontStyle="italic" app:fontWeight="500" app:font="@font/rubik_medium_italic" />
</font-family>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
5 changes: 0 additions & 5 deletions RNTester/android/app/src/main/res/font/srisakdi.xml

This file was deleted.

Binary file not shown.
Binary file not shown.
44 changes: 36 additions & 8 deletions RNTester/js/examples/Text/TextExample.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,41 @@ 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',
fontFamily: 'Rubik',
fontWeight: 'normal',
}}>
Rubik Regular
</Text>
<Text
style={{
fontFamily: 'Rubik',
fontWeight: '300',
}}>
Rubik Light
</Text>
<Text
style={{
fontFamily: 'Rubik',
fontWeight: '700',
}}>
Rubik Bold
</Text>
<Text
style={{
fontFamily: 'Rubik',
fontWeight: '500',
}}>
Rubik Medium
</Text>
<Text
style={{
fontFamily: 'Rubik',
fontStyle: 'italic',
fontWeight: '500',
}}>
Srisakdi Bold
Rubik Medium Italic
</Text>
</View>
</View>
Expand All @@ -203,15 +231,15 @@ class TextExample extends React.Component<{}> {
</RNTesterBlock>
<RNTesterBlock title="Font Weight">
<Text style={{fontWeight: 'bold'}}>Move fast and be bold</Text>
<Text style={{fontWeight: 'normal'}}>Move fast and be bold</Text>
<Text style={{fontWeight: 'normal'}}>Move fast and be normal</Text>
</RNTesterBlock>
<RNTesterBlock title="Font Style">
<Text style={{fontStyle: 'italic'}}>Move fast and be bold</Text>
<Text style={{fontStyle: 'normal'}}>Move fast and be bold</Text>
<Text style={{fontStyle: 'italic'}}>Move fast and be italic</Text>
<Text style={{fontStyle: 'normal'}}>Move fast and be normal</Text>
</RNTesterBlock>
<RNTesterBlock title="Font Style and Weight">
<Text style={{fontStyle: 'italic', fontWeight: 'bold'}}>
Move fast and be bold
Move fast and be both bold and italic
</Text>
</RNTesterBlock>
<RNTesterBlock title="Text Decoration">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ private static void apply(
}

if (family != null) {
typeface = ReactFontManager.getInstance().getTypeface(family, want, assetManager);
typeface = ReactFontManager.getInstance().getTypeface(family, want, weight, assetManager);
} else if (typeface != null) {
// TODO(t9055065): Fix custom fonts getting applied to text children with different style
typeface = Typeface.create(typeface, want);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
&& fontWeightString.charAt(0) <= '9'
&& fontWeightString.charAt(0) >= '1'
? 100 * (fontWeightString.charAt(0) - '0')
: -1;
: UNSET;
}

protected TextAttributes mTextAttributes;
Expand Down Expand Up @@ -487,14 +487,12 @@ public void setFontFamily(@Nullable String fontFamily) {
@ReactProp(name = ViewProps.FONT_WEIGHT)
public void setFontWeight(@Nullable String fontWeightString) {
int fontWeightNumeric =
fontWeightString != null ? parseNumericFontWeight(fontWeightString) : -1;
int fontWeight = UNSET;
if (fontWeightNumeric >= 500 || "bold".equals(fontWeightString)) {
fontWeight = Typeface.BOLD;
} else if ("normal".equals(fontWeightString)
|| (fontWeightNumeric != -1 && fontWeightNumeric < 500)) {
fontWeight = Typeface.NORMAL;
}
fontWeightString != null ? parseNumericFontWeight(fontWeightString) : UNSET;
int fontWeight = fontWeightNumeric != UNSET ? fontWeightNumeric : Typeface.NORMAL;

if (fontWeight == 700 || "bold".equals(fontWeightString)) fontWeight = Typeface.BOLD;
else if (fontWeight == 400 || "normal".equals(fontWeightString)) fontWeight = Typeface.NORMAL;

if (fontWeight != mFontWeight) {
mFontWeight = fontWeight;
markUpdated();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Typeface;
import android.os.Build;
import android.util.SparseArray;

import androidx.annotation.NonNull;
Expand Down Expand Up @@ -54,23 +55,32 @@ public static ReactFontManager getInstance() {
return sReactFontManagerInstance;
}

public @Nullable Typeface getTypeface(
String fontFamilyName,
int style,
AssetManager assetManager) {
return getTypeface(fontFamilyName, style, 0, assetManager);
}

public @Nullable Typeface getTypeface(
String fontFamilyName,
int style,
int weight,
AssetManager assetManager) {
if(mCustomTypefaceCache.containsKey(fontFamilyName)) {
Typeface typeface = mCustomTypefaceCache.get(fontFamilyName);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && weight >= 100 && weight <= 1000) {
return Typeface.create(typeface, weight, (style & Typeface.ITALIC) != 0);
}
return Typeface.create(typeface, style);
}

FontFamily fontFamily = mFontCache.get(fontFamilyName);
if (fontFamily == null) {
fontFamily = new FontFamily();
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);
Expand Down

1 comment on commit 3915c0f

@dulmandakh
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kelset could you please cherry pick into 0.60 if possible. Thank you

Please sign in to comment.