当时组内临时接到一个换字体库的需求,这个需求相对简单,因为手头有其他事情,同时之前也没换过字体库,就交给了同事去做了;现在有时间就好好充实下自己 ( 我写的也未必全对,如有不足可直接提出,相互探讨)
在正式开始以前,你首先需要告知产品经理和设计师,因为引入新的字体库存在版权问题,需要对方授权方可使用,否则涉及侵权;如果产品确定一定要改的话,请产品和设计提供相关字体库
- 业务需求&实现
- 业务需求
- 业务实现
- 静态实现
- 动态实现
- 基础认知
- 厂商字体
- 小米(Misans)
- 华为(HarmonyOS Sans)
- OPPO(OPPO SANS)
- 原理兴趣
开篇前没想到写一篇基础版的字体库相关内容,用了小俩天时间,越写越多,也参考了十几篇blog,有新有旧,希望该篇对你有所帮助
Look
:不知道你在看此篇时,是否有了解过字体库相关内容,我先行说一下,我在求知中遇到的问题
Android的默认字体到底是什么?为什么有的说是 Source Han Sans(思源)
,有的说是 Roboto
,有的说是 DroidSans、DroidSansFallback
?
关于这个问题,我翻了一堆文章,答案都东拼西凑、大同小异,并没有一个比较完善的解释,最后还是去外面找到一个合理的解释,我来统一整合一下吧(Hint:如果你想了解更多,也有一些个人兴趣,可前往基础认知中继续了解下,欢迎探讨~)
首先 Source Han Sans(思源)
、Roboto
、 DroidSans、DroidSansFallback
字体、字体库都是存在的,且都是存在于Android系统中的!
其中 Source Han Sans(思源)
适用于中文环境 & 中日韩三国,Roboto
适用于英文&数字, DroidSans、DroidSansFallback
适用于中日韩以外的国家 或 作为备用(默认)字体;(故知道国内用的是思源字体库+Roboto字体库即可
)
业务需求&实现
引入、以及使用新的字体库,都很简单,如果只是为了实现业务需要的话,只看该段即可;如果有兴趣,且时间充足的话可以大致过一下~
业务需求
因为是UI的设计需求
,我们主要看设计图相关数据信息即可
UI效果图
font-family(字体库): Roboto-Medium;
Hint:根据设计图可以看出使用到的主要是 Roboto字体中的 中等加粗字体
业务实现
关于字体库业务的实现方式,我看了一下实现方式,主要有静态实现(xml)和动态实现(代码设置)
,具体使用哪种方式取决于自己和业务场景的使用
因为俩种先方式针对于字体库的存储位置有所不同,故开设求知小课堂简单说明res、assets
同异
相同点:两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制
不同点:
- 引用资源的方式不同:
res/raw
中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;assets
文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager
类。 - 处理方式不同
- 子目录不同:
res/raw
不可以有目录结构,而assets
则可以有目录结构,也就是assets目录下可以再建立文件夹
根据涉及提供的字体库,解压后放在AndroidStudio
内可以直接看预览效果
综合实现效果
俩种实现方式的效果是统一的,只是静态实现支持预览,故统一效果图;
视图效果分别对应以下三类(我其实看不出太大区别,可能只有设计比较容易辨别)
默认字体
Roboto 普通字体
Roboto 加粗字体
静态实现
静态实现的优势在于使用方便,可以直接设置属性,同时支持直接观察设置效果;不足之处在于产品要求某些业务场景,需要动态切换控件的字体效果(千人千面)
- 在
res - 创建 font 文件夹
用于存放字体库
- 关于字体库的命令需要符合
命名规范
(对比动态实现命名有所不同)
错误命名
正确使用
xml
中引用字体库
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="0.00" />
<TextView
android:id="@+id/tv_text1"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:fontFamily="@font/roboto_regular"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="0.08" />
<TextView
android:id="@+id/tv_text2"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:fontFamily="@font/roboto_medium"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="66.66" />
</LinearLayout>
预览效果
动态实现
动态实现的方式同静态实现稍有不同,首先是资源存储的地方,其次是设置字体库的方式
- 创建
assets
文件夹
AndroidStudio
会自动提示
- 在
assets
文件夹下创建fonts
文件夹,主要用于存储字体库
- 字体库一般为
ttf
文件,我们将字体与放置于此即可,总体如下
调用方式
常规设置
package com.example.kotlindemo
import android.annotation.SuppressLint
import android.graphics.Typeface
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.want_text_display)
var t1 = findViewById<TextView>(R.id.tv_text1)
val regular = Typeface.createFromAsset(assets,"fonts/Roboto-Regular.ttf")
t1.typeface = regular;
}
}
单控件一般采用同一个字体库样式,这里是俩个控件的设置方式(设置方式相同),只所以多写一份是因为我引用了俩个字体库的样式,一个为roboto普通字体,一个为roboto加粗字体
package com.example.kotlindemo
import android.annotation.SuppressLint
import android.graphics.Typeface
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.want_text_display)
var t1 = findViewById<TextView>(R.id.tv_text1)
var t2 = findViewById<TextView>(R.id.tv_text2)
val regular = Typeface.createFromAsset(assets,"fonts/Roboto-Regular.ttf")
val medium = Typeface.createFromAsset(assets,"fonts/Roboto-Medium.ttf")
t1.typeface = regular;
t2.typeface = medium;
}
}
want_text_display
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="0.00" />
<TextView
android:id="@+id/tv_text1"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="0.08" />
<TextView
android:id="@+id/tv_text2"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="66.66" />
</LinearLayout>
留作备忘
我之前翻了一篇blog,看到说要设置ElegantTextHeight属性,否则高度会发生变化,但是我并未遇到相关场景,故再次留作备忘
// 应用字体
var typeFace = Typeface.createFromAsset(mContext.getAssets(),"fonts/sourcehanserifcn_regular.otf")
//这个不可缺少,不加tvtext高度变大很多 很不美观
tvtext.setElegantTextHeight(true)
tvtext.setTypeface(typeFace)
基础认知
Android 拥有着属于自己的默认字体库
,不过因为国内厂商较多,大多都会定制化字体
,所以显示效果各有不同,大多数时候字体并未完全统一
针对于我们常见的中文、英文、数字使用的字体库也有所不同
Android 默认字体
- 中文字体:
Source Han Sans / Noto
(思源黑体)
维基百科:思源黑体(英语:Source Han Sans,“思源”一词来自于成语“饮水思源”)是Adobe与Google所领导开发的开源字体家族,1.001及更早版本以Apache 2.0许可证许可,而1.002及更新版本则使用SIL开源字体授权,属于无衬线黑体。思源黑体于2014年7月16日首次发布,支持繁体中文、简体中文、日文及韩文,并且各有7种字体粗细。公开之时为当时涵盖字符数量最多的字体,44,666 个字符分属于 65,535 个字形中,此为OpenType字体技术的极限。
- 数字&英文字体:
Roboto
小课堂
DroidSansFallback
和思源黑体
是两种不同的字体,它们在 Android 系统中具有不同的作用和应用场景。
DroidSansFallback:DroidSansFallback
是 Android 系统中的一个字体库,用于支持多语言和字符集的显示
。它包含了广泛的 Unicode
字符覆盖范围,包括了一些不常见的字符和语言的字形。当系统无法找到适当的字体来显示特定字符时,它会使用 DroidSansFallback
来作为回退字体。这使得 Android 能够显示多种语言和符号,即使默认字体库(如 Roboto)没有包含对应的字符。
以下是Android安卓系统默认的几种字体:
Clockopia.ttf
系统默认待机时钟字体;DroidSansFallback.ttf
系统默认中文字体;DroidSans.ttf
系统默认英文字体;DroidSans-Bold.ttf
系统默认英文粗字体;
思源黑体:思源黑体是一种由 Adobe
和 Google
共同开发的开源字体,用于支持中日韩(CJK)语言的显示。它包含了汉字、日文假名和韩文字符,具有广泛的覆盖范围。思源黑体在设计上注重保持字形的清晰度和可读性,同时适应不同的屏幕尺寸和分辨率。在一些中日韩语言环境下,Android 系统会使用思源黑体作为默认的字体来显示相应的文字内容。
不论我们使用哪种字体库,一般字体库都会提供字体的多种样式,例如常规、加粗等,例如 Regular、Italic、Bold、Bold-italic、Light、Light-italic、Thin、Thin-italic、Condensed regular、Condensed italic、Condensed bold、Condensed bold-italic
作为队友,有必要了解下 IOS 默认字体
- 中文字体:
PingFang SC
- 数字&英文字体:
.SF UI Text、.SF UI Display
默默 copy 俩张图
以中文字体来做对比,可以看出平方对比思源黑体,笔画更细、字怀更大、字体使用弧度更少,偏旁所占字面更小
(说实话,还得设计来看,我基本看不出什么太大区别…)。
关于Roboto字体的一些补充介绍
这部分内容偏官方简介,仅做了解即可,无需细读,以下介绍均针对于Android客户端
字体特点
清晰的字形
:Roboto字体有着非常清晰的字形,这使得它在阅读和书写时非常舒适。可读性强
:Roboto字体具有很好的可读性,这意味着在大多数应用程序中它都能很好地适用。平衡的间距
:Roboto字体在行与行之间的间距上也有很好的平衡。这意味着文本在屏幕上的布局非常均匀,看起来非常整齐。广泛的可用性
:Roboto字体是一种开源字体,因此它在Android开源项目中被广泛使用。这使得它在各种设备和屏幕分辨率上都能很好地适用。
字体优点
看起来专业
:使用Roboto字体可以使应用程序看起来更加专业化。它的清晰字形和平衡的间距使得文本在屏幕上看起来更加清晰。提高可读性
:由于Roboto字体的可读性很好,因此在阅读和书写时非常舒适,这也意味着应用程序的可用性得到了提高。减少屏幕分辨率变化
:由于Roboto字体在各种设备和屏幕分辨率上都能很好地适用,因此应用程序在适应不同屏幕大小时不会产生过大的影响。延长设备电池寿命
:一些研究表明,使用Roboto字体可以延长设备电池寿命。这是因为较暗的字体可以减少屏幕亮度的需求,从而减少了电池的消耗。
字体不足
应用程序的可读性降低
:如果应用程序中的文本使用了不太一样的字体,那么可能会导致应用程序的可读性降低。应用程序的可用性降低
:如果应用程序中的文本使用了Roboto字体,而设备屏幕分辨率较低,那么可能会导致应用程序的可用性降低。设备电池消耗增加
:有一些研究表明,使用Roboto字体可能会导致设备电池消耗增加。这是因为较暗的字体可能会导致屏幕亮度的需求增加,从而增加了电池的消耗。
厂商字体
Anddroid本身的定制性较强,早期换字体的时候基本上需要root,如今手机自带这个功能,各厂商也有了足够的权限,所以在看到大家对系统默认字体不是很喜欢时,就致力研发自家的字体;针对国内的厂商大多都有自定的字体,例如
Misans
、OPPO SANS
、HarmonyOS Sans
等一些手机厂商默认的字体。这些字体不仅支持中文显示,连西文(如英文)都能完美显示。
在一篇文章内看到介绍了 各大手机厂商的默认字体,此处仅做一些关键信息摘要
这位朋友说字体好不好,还需注意这三个方面:字符数要多(照顾部分生僻字)、字重齐全(粗细均匀)、OpenType支持(字符根据情况自动调整,使其看起来更加美观)。
我们来看看主流的这三款字体哪个更好看吧!这里再说明一下,这三款字体都是汉仪定制字体,因此字体不全是手机厂商定制。
小米(Misans)
针对于MIUI13
里面宣传的全新系统字体MiSans
,全方位优化中英文及数字设计,字形简约,视觉清晰,阅读舒适。
其实这个MiSans
算是黑体的变种
。虽然也是黑体,但是在一些细节处能看出是真下了功夫
- 笔型平直有力
- 设计更加简约
- 减少视觉负担
- 更有利于屏幕显示
- 支持OpenType功能
MiSan
一出,尤其是在一些长文和标点符号比较多的场景下,明显所谓的高级感更强,而鸿蒙字体与其相比就显得普通了一些。
华为(HarmonyOS Sans)
- 支持更多的语言;
- 对斜体和繁体中文有专门的加强字体;
- 中英文混排、文字和标点符号混排感觉也是相当优秀,不会出现很生硬的错行,但是字重比小米MiSans要少,只有6种字重。
OPPO(OPPO SANS)
- 全新骨架
- 中宫自然舒适
- 结构稳定
- 字形舒展
- 强化了屏幕显示的易读性和美观性
原理兴趣
Android字体工作原理
android字体由android 2D图形引擎skia
实现,并在Zygote
的Preloading classes
中对系统字体进行load
。
相关文件有:skTypeface.cpp
和skFontHost_android.cpp
,其中后者是skia针对android平台字体实现的port
。主要的变量有:
struct FontInitRec {const char*
fFileName;const char* const* fNames;
// null-terminated list};struct FamilyRec {FamilyRec* fNext;SkTypeface* fFaces[5];};
//uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];load_system_fonts()@skFontHost_android.cpp
load系统中所有的字体并给每种字体分配唯一的ID,并将字体分为两种:FamilyFonts
和FallbackFonts
,skPaint
通过应用程序设置的字体(Typeface
)所对应的ID最终实现字符的显示。
替换Android默认的汉字字体
在android
系统中,DroidSans
是默认字体,只包含西方字符,应用程序默认情况下都会调用它,而DroidSansFallback
包含了东亚字符,当需要显示的字符在DroidSans
字体中不存在(如:汉字)时,即没有对应编码的字符时,系统会到DroidSansFallback
中去找相应编码的字符,如果找到,则使用DroidSansFallback
字体来显示它,如果仍找不到该编码对应的字符,则无法在屏幕上显示该字符。
为android系统添加一种默认字体,类似“sans”,“serif”,“monospace
”
在android系统中,默认的中文字体只有一种:DroidSansFallback.ttf
,如果想在android应用程序中随意设置想要的中文字体,除了在应用程序中通过assets目录引入字体文件外,还可以通过增加android默认字体的方式来实现。添加步骤大致如下:
- 在
frameworks/base/data/fonts
目录下添加字体文件,例如Driod-kaishu.ttf
; - 在
skia
中增加楷书这一字体,需要修改的文件主要有skFontHost.cpp、skTypeface.cpp、Typeface.java
等; - 在
java
层添加楷书字体相关API,需要修改的文件主要有typeface.java和textview.java
; - 编译SDK
- 将新生成的sdk导入eclipse,在eclipse中即可通过
setTypeface(Typeface.KAISHU)
和android:typeface=(“kaishu”)
两种方式设置自己添加的字体。