Android字体学习
1. sdk自带字体
<TextView
android:id="@+id/tv_show_normal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="SDK自带字体:normal"
android:textColor="#333333"
android:textSize="25sp"
android:typeface="normal" />
<TextView
android:id="@+id/tv_show_monospace"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="SDK自带字体:monospace"
android:textColor="#333333"
android:textSize="25sp"
android:typeface="monospace" />
<TextView
android:id="@+id/tv_show_sans"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="SDK自带字体:sans"
android:textColor="#333333"
android:textSize="25sp"
android:typeface="sans" />
<TextView
android:id="@+id/tv_show_serif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="SDK自带字体:serif"
android:textColor="#333333"
android:textSize="25sp"
android:typeface="serif" />
默认自带的字体就四种,如上图,左边是没有设置系统字体的效果,右边设置了系统字体,可以看出要跟随系统字体,必须设置normal和sans(应该是这样吧,其它手机没试过,我测试机是OPPO)。
int style = Typeface.NORMAL;
switch (v.getId()) {
case R.id.tv_bold:
style = Typeface.BOLD;
break;
case R.id.tv_italic:
style = Typeface.ITALIC;
break;
case R.id.tv_italic_bold:
style = Typeface.BOLD_ITALIC;
break;
}
normal.setTypeface(Typeface.DEFAULT, style);
monospace.setTypeface(Typeface.MONOSPACE, style);
sans.setTypeface(Typeface.SANS_SERIF, style);
serif.setTypeface(Typeface.SERIF, style);
代码设置可以如上进行设置。
2. 三方字体
<TextView
android:id="@+id/tv_gtw"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/gtw"
android:padding="10dp"
android:text="三方字体:GNUTypewriter"
android:textColor="#333333"
android:textSize="25sp" />
<TextView
android:id="@+id/tv_oswald"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/oswald_stencbab"
android:padding="10dp"
android:text="三方字体:Oswald"
android:textColor="#333333"
android:textSize="25sp" />
<TextView
android:id="@+id/tv_roboto_bold"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/roboto_bold"
android:padding="10dp"
android:text="三方字体:Roboto(Bold)"
android:textColor="#333333"
android:textSize="25sp" />
<TextView
android:id="@+id/tv_roboto_condensed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/roboto_condensed_regular"
android:padding="10dp"
android:text="三方字体:Roboto Condensed"
android:textColor="#333333"
android:textSize="25sp" />
<TextView
android:id="@+id/tv_roboto_thin_italic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/roboto_thin_italic"
android:padding="10dp"
android:text="三方字体:Roboto-ThinItalic"
android:textColor="#333333"
android:textSize="25sp" />
<TextView
android:id="@+id/tv_roboto_thin_italic_compare"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/roboto_thin_italic"
android:padding="10dp"
android:text="三方字体:Roboto-ThinItalic. fontFamily有比typeface更高的优先级"
android:textColor="#333333"
android:textSize="25sp"
android:typeface="normal" />
以上四图分别对应textStyle的normal;bold;italic;italic|bold. 可以看出部分字体并不买textStyle的账(应该是字体资源文件本身的支持问题),所以三方字体的使用要注意能不能满足需求。
3. 三方字体动态加载
public void getFromResource() {
res.setTypeface(ResourcesCompat.getFont(activity, R.font.roboto_bold));
}
public void getFromAssets() {
assets.setTypeface(Typeface.createFromAsset(activity.getAssets(), "roboto_thin_italic.ttf"));
}
public void getFromFile() {
new Thread() {
@Override
public void run() {
File f = null;
try {
InputStream is = activity.getAssets().open("gtw.ttf");
f = new File(activity.getExternalCacheDir(), "font" + File.separator + "gtw.ttf");
if (!f.exists()) {
if (f.getParentFile().exists() || f.getParentFile().mkdirs()) {
FileOutputStream fos = new FileOutputStream(f);
byte[] b = new byte[1024 * 8];
int readLen = -1;
while ((readLen = is.read(b)) > 0) {
fos.write(b, 0, readLen);
}
}
}
} catch (IOException ignore) {
}
Typeface typeface = null;
try {
typeface = Typeface.createFromFile(f);
} catch (Exception e) {
if (f != null) {
f.delete();
}
}
final Typeface forUse = typeface;
file.post(new Runnable() {
@Override
public void run() {
if (forUse == null) {
return;
}
file.setTypeface(forUse);
}
});
}
}.start();
}
三方字体可以直接配在res/font目录下,也可以丢在assets或者直接从网上下载到某个目录下,加载方式如上代码。
private void updateTextStyle() {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) {
return;
}
Typeface.Builder builder = new Typeface.Builder(activity.getAssets(), "roboto_condensed_regular.ttf");
// 不咋好使
// FontVariationAxis wght = new FontVariationAxis("wght", 900);
// FontVariationAxis ital = new FontVariationAxis("ital", 1f);
//
// builder.setFontVariationSettings(new FontVariationAxis[] {wght, ital});
// 字体资源文件是字体集合时指定其中一个,如果不是可以不调用,调用0也行
builder.setTtcIndex(0);
builder.setItalic(true);
builder.setWeight(500);
text.setTypeface(builder.build());
}
也可以通过Typeface.Builder来配置字体粗细(wght,0-1000,100梯度)和倾斜(ital,1和其它值)。
这玩意sdk版本要求太高基本上价值不大,目前仅支持wght和ital,wdth、slnt和opsz并不支持(可以查看FontFileUtil.analyzeStyle的源码来确认这点)这五个字段是啥可以看这里
setTtcIndex针对三方字体文件是字体组的情况,index是几就指向字体组的第几个字体,超过字体组的数量也没啥问题,会使用系统默认字体(没找到这种资源,感觉没啥用)
setItalic是否倾斜,setWeight字体粗细设置,通过setFontVariationSettings设置有点不靠谱,粗细可以,倾斜不知道为啥不起作用。还有这个东西似乎有缓存不能动态变更粗细和倾斜(感觉更没用了)。
4. spannable支持
private CharSequence getTargetText() {
String meetingName = getString(R.string.meeting_name);
String area = getString(R.string.area);
String room = getString(R.string.room);
String completeText = String.format(Locale.getDefault(), getString(R.string.test_long_text), meetingName, area, room);
SpannableString res = new SpannableString(completeText);
changeTextStyle(res, completeText, meetingName, R.font.gtw, Typeface.BOLD);
changeTextStyle(res, completeText, area, R.font.oswald_stencbab, Typeface.ITALIC);
changeTextStyle(res, completeText, room, R.font.roboto_condensed_regular, Typeface.BOLD_ITALIC);
return res;
}
private void changeTextStyle(SpannableString res, String completeText, String text, int tf, int style) {
int start = completeText.indexOf(text);
int end = start + text.length();
if (start >= end) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
res.setSpan(new TypefaceSpan(getTypeface(tf)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
// 仅支持系统字体
res.setSpan(new TypefaceSpan("serif"), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
}
res.setSpan(new StyleSpan(style), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
}
看上面代码就知道支持得不好,三方字体必须Android28以上,以下只能改系统字体(那四个字体基本上没啥区别),反正就很无奈,溜了溜了。