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

fix(android): font weight compatible with version 2.x #3948

Merged
merged 2 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/api/style/appearance.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
| ------ | -------- | --- |
| number \| string | 否 | Android、iOS

> Android API 28 以下仅支持 `normal`(`400`) 和 `bold`(`700`)两种字重,其它字重效果需配合 `fontFamily` 实现。
> Android API 28 以下仅支持 `normal`和 `bold` 两种字重,其它字重效果需配合 `fontFamily` 实现,Android API 28 及以上可以支持设置`1` - `1000`的字重值

# letterSpacing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const styles = StyleSheet.create({
fontSize: 14,
lineHeight: 18,
color: 'black',
fontWeight: 'normal'
},
buttonBar: {
flexDirection: 'row',
Expand All @@ -54,6 +55,7 @@ const styles = StyleSheet.create({
borderStyle: 'solid',
flexGrow: 1,
flexShrink: 1,
justifyContent: 'center',
},
buttonText: {
lineHeight: 24,
Expand All @@ -72,6 +74,7 @@ export default class TextExpo extends React.Component {
super(props);
this.state = {
fontSize: 16,
fontWeight: '400',
textShadowColor: 'grey',
textShadowOffset: {
x: 1,
Expand All @@ -83,12 +86,36 @@ export default class TextExpo extends React.Component {
};
this.incrementFontSize = this.incrementFontSize.bind(this);
this.decrementFontSize = this.decrementFontSize.bind(this);
this.incrementFontWeight = this.incrementFontWeight.bind(this);
this.decrementFontWeight = this.decrementFontWeight.bind(this);
this.incrementLine = this.incrementLine.bind(this);
this.decrementLine = this.decrementLine.bind(this);
this.changeMode = this.changeMode.bind(this);
this.changeColor = this.changeColor.bind(this);
}
incrementFontWeight() {
const { fontWeight } = this.state;
if (fontWeight == '1000') {
return;
}
var weightNumber = parseInt(fontWeight, 10);
weightNumber += 100;
this.setState({
fontWeight: weightNumber.toString(),
});
}

decrementFontWeight() {
const { fontWeight } = this.state;
if (fontWeight === '100') {
return;
}
var weightNumber = parseInt(fontWeight, 10);
weightNumber -= 100;
this.setState({
fontWeight: weightNumber.toString(),
});
}
incrementFontSize() {
const { fontSize } = this.state;
if (fontSize === 24) {
Expand Down Expand Up @@ -140,7 +167,7 @@ export default class TextExpo extends React.Component {
}

render() {
const { fontSize, textShadowColor, textShadowOffset, numberOfLines, ellipsizeMode, breakStrategy,
const { fontSize, fontWeight, textShadowColor, textShadowOffset, numberOfLines, ellipsizeMode, breakStrategy,
scrollColor } = this.state;
const renderTitle = title => (
<View style={styles.itemTitle}>
Expand Down Expand Up @@ -194,6 +221,18 @@ export default class TextExpo extends React.Component {
<Text style={styles.buttonText}>缩小字体</Text>
</View>
</View>
{renderTitle('fontWeight')}
<View style={[styles.itemContent, { height: 125, color: 'blue', fontFamily: 'not-support-fontstyle' }]}>
<Text style={[styles.normalText, { fontWeight }]}>
{ `Text fontWeight is ${fontWeight}` }
</Text>
<View style={styles.button} onClick={this.incrementFontWeight}>
<Text style={styles.buttonText}>加粗字体</Text>
</View>
<View style={styles.button} onClick={this.decrementFontWeight}>
<Text style={styles.buttonText}>减细字体</Text>
</View>
</View>
{renderTitle('fontStyle')}
<View style={[styles.itemContent, { height: 100 }]}>
<Text style={[styles.normalText, { fontStyle: 'normal' }]}>Text fontStyle is normal</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public class HippyTextInput extends AppCompatEditText implements HippyViewBase,
private int mListenerFlag = 0;
private ReactContentSizeWatcher mReactContentSizeWatcher = null;
private boolean mItalic = false;
private int mFontWeight = TypeFaceUtil.WEIGHT_NORMAL;
private String mFontWeight = TypeFaceUtil.TEXT_FONT_STYLE_NORMAL;
private float mLineSpacingMultiplier = 1.0f;
private float mLineSpacingExtra = 0.0f;
private int mLineHeight = 0;
Expand Down Expand Up @@ -763,23 +763,8 @@ public void setFontFamily(String family) {
}

public void setFontWeight(String weight) {
int fontWeight;
if (TextUtils.isEmpty(weight) || TypeFaceUtil.TEXT_FONT_STYLE_NORMAL.equals(weight)) {
// case normal
fontWeight = TypeFaceUtil.WEIGHT_NORMAL;
} else if (TypeFaceUtil.TEXT_FONT_STYLE_BOLD.equals(weight)) {
// case bold
fontWeight = TypeFaceUtil.WEIGHT_BOLE;
} else {
// case number
try {
fontWeight = Math.min(Math.max(1, Integer.parseInt(weight)), 1000);
} catch (NumberFormatException ignored) {
fontWeight = TypeFaceUtil.WEIGHT_NORMAL;
}
}
if (fontWeight != mFontWeight) {
mFontWeight = fontWeight;
if (!mFontWeight.equals(weight)) {
mFontWeight = weight;
mShouldUpdateTypeface = true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,25 @@
public class TextStyleSpan extends MetricAffectingSpan {

private final boolean mItalic;
private final int mWeight;
private final String mFontWeight;
private final String mFontFamily;
private final FontAdapter mFontAdapter;

public TextStyleSpan(boolean italic, int fontWeight, String fontFamily,
public TextStyleSpan(boolean italic, String fontWeight, String fontFamily,
FontAdapter adapter) {
mItalic = italic;
mWeight = fontWeight;
mFontWeight = fontWeight;
mFontFamily = fontFamily;
mFontAdapter = adapter;
}

@Override
public void updateDrawState(TextPaint textPaint) {
TypeFaceUtil.apply(textPaint, mItalic, mWeight, mFontFamily, mFontAdapter);
TypeFaceUtil.apply(textPaint, mItalic, mFontWeight, mFontFamily, mFontAdapter);
}

@Override
public void updateMeasureState(TextPaint textPaint) {
TypeFaceUtil.apply(textPaint, mItalic, mWeight, mFontFamily, mFontAdapter);
TypeFaceUtil.apply(textPaint, mItalic, mFontWeight, mFontFamily, mFontAdapter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@

import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.text.TextUtils;

import android.util.SparseArray;
import androidx.annotation.ChecksSdkIntAtLeast;
import androidx.annotation.Nullable;

import com.tencent.mtt.hippy.utils.ContextHolder;
Expand All @@ -43,26 +43,25 @@ public class TypeFaceUtil {
private static final String[] FONT_EXTENSIONS = {".ttf", ".otf"};
private static final String FONTS_PATH = "fonts/";
private static final Map<String, SparseArray<Typeface>> sFontCache = new HashMap<>();
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)
private static final boolean SUPPORT_FONT_WEIGHT = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;

/**
* @deprecated use {@link #getTypeface(String, int, boolean, FontAdapter)} instead
* @deprecated use {@link #getTypeface(String, String, boolean, FontAdapter)} instead
*/
@Deprecated
public static Typeface getTypeface(String fontFamilyName, int style,
@Nullable FontAdapter fontAdapter) {
boolean italic = (style & Typeface.ITALIC) != 0;
int weightNumber = (style & Typeface.BOLD) != 0 ? WEIGHT_BOLE : WEIGHT_NORMAL;
return getTypeface(fontFamilyName, weightNumber, italic, fontAdapter);
String weight = (style & Typeface.BOLD) != 0 ? TEXT_FONT_STYLE_BOLD : TEXT_FONT_STYLE_NORMAL;
return getTypeface(fontFamilyName, weight, italic, fontAdapter);
}

public static Typeface getTypeface(String fontFamilyName, int weight, boolean italic,
public static Typeface getTypeface(String fontFamilyName, String weight, boolean italic,
@Nullable FontAdapter fontAdapter) {
final int style = toStyle(weight, italic);
int weightNumber = getWeightNumber(weight);
final int style = toStyle(weight, weightNumber, italic);
Typeface typeface = (fontAdapter != null) ? fontAdapter.getCustomTypeface(fontFamilyName, style) : null;
if (typeface == null) {
final int key = SUPPORT_FONT_WEIGHT ? ((weight << 1) | (italic ? 1 : 0)) : style;
final int key = (weightNumber > 0) ? ((weightNumber << 1) | (italic ? 1 : 0)) : style;
SparseArray<Typeface> cache = sFontCache.get(fontFamilyName);
if (cache == null) {
cache = new SparseArray<>(4);
Expand All @@ -71,7 +70,7 @@ public static Typeface getTypeface(String fontFamilyName, int weight, boolean it
typeface = cache.get(key);
}
if (typeface == null) {
typeface = createTypeface(fontFamilyName, weight, italic, fontAdapter);
typeface = createTypeface(fontFamilyName, weightNumber, style, italic, fontAdapter);
if (typeface != null) {
cache.put(key, typeface);
}
Expand All @@ -80,9 +79,8 @@ public static Typeface getTypeface(String fontFamilyName, int weight, boolean it
return typeface;
}

private static Typeface createTypeface(String fontFamilyName, int weight, boolean italic,
private static Typeface createTypeface(String fontFamilyName, int weightNumber, int style, boolean italic,
@Nullable FontAdapter fontAdapter) {
final int style = toStyle(weight, italic);
final String extension = EXTENSIONS[style];
final String[] familyNameList;
if (fontFamilyName.indexOf(',') == -1) {
Expand Down Expand Up @@ -113,8 +111,8 @@ private static Typeface createTypeface(String fontFamilyName, int weight, boolea
try {
Typeface typeface = Typeface.createFromAsset(ContextHolder.getAppContext().getAssets(), fileName);
if (typeface != null && !typeface.equals(Typeface.DEFAULT)) {
if (SUPPORT_FONT_WEIGHT) {
return Typeface.create(typeface, weight, italic);
if (VERSION.SDK_INT >= VERSION_CODES.P && weightNumber > 0) {
return Typeface.create(typeface, weightNumber, italic);
}
// "bold" has no effect on api level < P, prefer to use `Paint.setFakeBoldText(boolean)`
return italic ? Typeface.create(typeface, Typeface.ITALIC) : typeface;
Expand All @@ -138,46 +136,57 @@ private static Typeface createTypeface(String fontFamilyName, int weight, boolea
}
}
}

final Typeface systemDefault = Typeface.create(Typeface.DEFAULT, style);
for (String splitName : familyNameList) {
Typeface typeface = Typeface.create(splitName, style);
if (typeface != null && !typeface.equals(systemDefault)) {
return SUPPORT_FONT_WEIGHT ? Typeface.create(typeface, weight, italic) : typeface;
if (VERSION.SDK_INT >= VERSION_CODES.P && weightNumber > 0) {
return Typeface.create(typeface, weightNumber, italic);
}
return typeface;
}
}
return SUPPORT_FONT_WEIGHT ? Typeface.create(systemDefault, weight, italic) : systemDefault;
return (VERSION.SDK_INT >= VERSION_CODES.P && weightNumber > 0) ?
Typeface.create(systemDefault, weightNumber, italic) : systemDefault;
}

private static int toStyle(int weight, boolean italic) {
return weight < WEIGHT_BOLE ?
(italic ? Typeface.ITALIC : Typeface.NORMAL) :
(italic ? Typeface.BOLD_ITALIC : Typeface.BOLD);
private static int getWeightNumber(String weight) {
int weightNumber = 0;
try {
weightNumber = Math.min(Math.max(1, Integer.parseInt(weight)), 1000);
} catch (NumberFormatException ignored) {
// Weight supports setting non numeric strings
}
return weightNumber;
}

/**
* @deprecated use {@link #apply(Paint, boolean, int, String, FontAdapter)} instead
*/
@Deprecated
public static void apply(Paint paint, int style, int weight, String family,
@Nullable FontAdapter fontAdapter) {
boolean italic = style == Typeface.ITALIC;
int weightNumber = weight == Typeface.BOLD ? WEIGHT_BOLE : WEIGHT_NORMAL;
apply(paint, italic, weightNumber, family, fontAdapter);
private static int toStyle(String weight, int weightNumber, boolean italic) {
if (weight.equals(TEXT_FONT_STYLE_NORMAL)) {
return italic ? Typeface.ITALIC : Typeface.NORMAL;
} else if (weight.equals(TEXT_FONT_STYLE_BOLD)) {
return italic ? Typeface.BOLD_ITALIC : Typeface.BOLD;
} else {
return weightNumber < WEIGHT_BOLE ?
(italic ? Typeface.ITALIC : Typeface.NORMAL) :
(italic ? Typeface.BOLD_ITALIC : Typeface.BOLD);
}
}

public static void apply(Paint paint, boolean italic, int weight, String familyName,
public static void apply(Paint paint, boolean italic, String weight, String familyName,
@Nullable FontAdapter fontAdapter) {
Typeface typeface;
int weightNumber = getWeightNumber(weight);
if (TextUtils.isEmpty(familyName)) {
final Typeface base = paint.getTypeface();
typeface = SUPPORT_FONT_WEIGHT
? Typeface.create(base, weight, italic)
: Typeface.create(base, toStyle(weight, italic));
if (VERSION.SDK_INT >= VERSION_CODES.P && weightNumber > 0) {
typeface = Typeface.create(base, weightNumber, italic);
} else {
typeface = Typeface.create(base, toStyle(weight, weightNumber, italic));
}
} else {
typeface = getTypeface(familyName, weight, italic, fontAdapter);
}
if (weight >= WEIGHT_BOLE && typeface != null && !typeface.isBold()) {
if (weightNumber >= WEIGHT_BOLE && typeface != null && !typeface.isBold()) {
paint.setFakeBoldText(true);
}
paint.setTypeface(typeface);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public class TextVirtualNode extends VirtualNode {
protected int mColor = Color.BLACK;
protected int mNumberOfLines;
protected boolean mItalic = false;
protected int mFontWeight = TypeFaceUtil.WEIGHT_NORMAL;
protected String mFontWeight = TypeFaceUtil.TEXT_FONT_STYLE_NORMAL;
protected int mFontSize = (int) Math.ceil(PixelUtil.dp2px(NodeProps.FONT_SIZE_SP));
protected int mShadowColor = TEXT_SHADOW_COLOR_DEFAULT;
protected float mShadowOffsetDx = 0.0f;
Expand Down Expand Up @@ -183,23 +183,8 @@ public void setFontFamily(String family) {
@SuppressWarnings("unused")
@HippyControllerProps(name = NodeProps.FONT_WEIGHT, defaultType = HippyControllerProps.STRING)
public void setFontWeight(String weight) {
int fontWeight;
if (TextUtils.isEmpty(weight) || TypeFaceUtil.TEXT_FONT_STYLE_NORMAL.equals(weight)) {
// case normal
fontWeight = TypeFaceUtil.WEIGHT_NORMAL;
} else if (TypeFaceUtil.TEXT_FONT_STYLE_BOLD.equals(weight)) {
// case bold
fontWeight = TypeFaceUtil.WEIGHT_BOLE;
} else {
// case number
try {
fontWeight = Math.min(Math.max(1, Integer.parseInt(weight)), 1000);
} catch (NumberFormatException ignored) {
fontWeight = TypeFaceUtil.WEIGHT_NORMAL;
}
}
if (fontWeight != mFontWeight) {
mFontWeight = fontWeight;
if (!mFontWeight.equals(weight)) {
mFontWeight = weight;
markDirty();
}
}
Expand Down
Loading