正常设置字体样式如下:
SpannableString sStr = new SpannableString("这个是设置字体样式的")
sStr.setSpan(new TypefaceSpan("default"), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new TypefaceSpan("default-bold"), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new TypefaceSpan("monospace"), 4, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
在TypefaceSpan源码中(如下)
public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan {
@Nullable
private final String mFamily;
@Nullable
private final Typeface mTypeface;
/**
* Constructs a {@link TypefaceSpan} based on the font family. The previous style of the
* TextPaint is kept. If the font family is null, the text paint is not modified.
*
* @param family The font family for this typeface. Examples include
* "monospace", "serif", and "sans-serif"
*/
public TypefaceSpan(@Nullable String family) {
this(family, null);
}
/**
* Constructs a {@link TypefaceSpan} from a {@link Typeface}. The previous style of the
* TextPaint is overridden and the style of the typeface is used.
*
* @param typeface the typeface
*/
public TypefaceSpan(@NonNull Typeface typeface) {
this(null, typeface);
}
/**
* Constructs a {@link TypefaceSpan} from a parcel.
*/
public TypefaceSpan(@NonNull Parcel src) {
mFamily = src.readString();
mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
}
private TypefaceSpan(@Nullable String family, @Nullable Typeface typeface) {
mFamily = family;
mTypeface = typeface;
}
@Override
public int getSpanTypeId() {
return getSpanTypeIdInternal();
}
/** @hide */
@Override
public int getSpanTypeIdInternal() {
return TextUtils.TYPEFACE_SPAN;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
writeToParcelInternal(dest, flags);
}
/** @hide */
@Override
public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
dest.writeString(mFamily);
LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
}
/**
* Returns the font family name set in the span.
*
* @return the font family name
* @see #TypefaceSpan(String)
*/
@Nullable
public String getFamily() {
return mFamily;
}
/**
* Returns the typeface set in the span.
*
* @return the typeface set
* @see #TypefaceSpan(Typeface)
*/
@Nullable
public Typeface getTypeface() {
return mTypeface;
}
@Override
public void updateDrawState(@NonNull TextPaint ds) {
updateTypeface(ds);
}
@Override
public void updateMeasureState(@NonNull TextPaint paint) {
updateTypeface(paint);
}
private void updateTypeface(@NonNull Paint paint) {
if (mTypeface != null) {
paint.setTypeface(mTypeface);
} else if (mFamily != null) {
applyFontFamily(paint, mFamily);
}
}
private void applyFontFamily(@NonNull Paint paint, @NonNull String family) {
int style;
Typeface old = paint.getTypeface();
if (old == null) {
style = Typeface.NORMAL;
} else {
style = old.getStyle();
}
final Typeface styledTypeface = Typeface.create(family, style);
int fake = style & ~styledTypeface.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
}
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
paint.setTypeface(styledTypeface);
}
}
构造函数中参数可以传String family和Typeface typeface family相当于如上的default ,default-default-bold 等 而typeface可以设置自定义下载的字体,比如
Typeface tf = Typeface.createFromAsset(getAssets(), "test字体.ttf");
sStr.setSpan(new TypefaceSpan("tf"), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
在实际开发项目中如上设置 new TypefaceSpan("tf") 字体样式时,在Android 9.0以下时会如下报错
java.lang.NoSuchMethodError
No direct method <init>(Landroid/graphics/Typeface;)V in class Landroid/text/style/TypefaceSpan;
or its super classes (declaration of 'android.text.style.TypefaceSpan' appears in /system/framework/framework.jar!classes2.dex)
提示framework.jar 中没有发现直接调用new TypefaceSpan("tf") 这个方法。需要自定义CustomTypefaceSpan :如下
public class CustomTypefaceSpan extends TypefaceSpan {
private final Typeface newType;
public CustomTypefaceSpan(String family, Typeface type) {
super(family);
newType = type;
}
@Override
public void updateDrawState(TextPaint ds) {
setCustomTypeFace(ds, newType);
}
@Override
public void updateMeasureState(TextPaint paint) {
setCustomTypeFace(paint, newType);
}
private void setCustomTypeFace(Paint paint, Typeface tf) {
if (tf == null || paint == null)return;
paint.setTypeface(tf);
}
}
设置字体样式改成如下:
Typeface tf = Typeface.createFromAsset(getAssets(), "test字体.ttf");
sStr.setSpan(new CustomTypefaceSpan("tf"), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
通过不同的安卓版本测试 未报如上错误日志;
当前问题基于应用内遇到的处理方法,以上方式如果存在缺陷或者兼容性问题,欢迎一起讨论并完善。谢谢
安卓字体样式设置java.lang.NoSuchMethodErrorNo direct method <init>(Landroid/graphics/Typeface;)
于 2022-07-26 15:41:55 首次发布