Android中FontAwesome 5三个TTF文件整合方案问询
解决FontAwesome 5多TTF文件在Android自定义FontManager中的适配问题
针对你目前的场景——现有FontManager仅支持单TTF文件,但FontAwesome 5拆分为regular、solid、brand三个字体文件,我提供两种可行方案,你可以根据需求选择:
方案一:合并三个TTF文件为单个文件(零代码改动)
如果想完全沿用现有代码结构,不需要修改任何逻辑,可以用字体编辑工具把三个FontAwesome 5的TTF文件合并成一个:
- 下载并打开FontForge(免费开源的字体编辑工具)
- 分别导入
fa-regular-400.ttf、fa-solid-900.ttf、fa-brands-400.ttf三个文件 - 将后两个字体中的所有字形(Glyphs)复制粘贴到第一个字体文件中(FontAwesome 5的不同风格图标Unicode编码无冲突,不用担心覆盖)
- 导出合并后的新TTF文件,命名为
fontawesome-webfont.ttf替换原文件 - 重启项目后,原有代码无需任何改动即可调用所有风格的图标
方案二:修改FontManager与自定义控件,自动匹配对应字体(更灵活推荐)
如果不想修改字体文件,希望根据图标自动选择对应字体,可以通过修改现有代码实现:
第一步:升级FontManager,添加字体缓存与字体匹配逻辑
object FontManager { private val ROOT = "fonts/" val FA_REGULAR = ROOT + "fa-regular-400.ttf" val FA_SOLID = ROOT + "fa-solid-900.ttf" val FA_BRAND = ROOT + "fa-brands-400.ttf" // 缓存Typeface避免重复创建,提升性能 private val typefaceCache = mutableMapOf<String, Typeface>() fun getTypeface(context: Context, font: String): Typeface { return typefaceCache.getOrPut(font) { Typeface.createFromAsset(context.assets, font) } } // 根据图标字符的Unicode范围,判断应该使用哪个字体 private fun getFontPathForChar(char: Char): String { return when (char.code) { // 品牌图标Unicode范围(参考FontAwesome官方映射表) in 0xF000..0xF0FF -> FA_BRAND // 常规风格图标范围 in 0xF100..0xF1FF, 0xF204, 0xF20A -> FA_REGULAR // 实心风格图标范围 else -> FA_SOLID } } // 给单个TextView设置对应字体 fun applyIconFont(textView: TextView, context: Context) { val text = textView.text ?: return if (text.isNotEmpty()) { val targetFont = getFontPathForChar(text[0]) textView.typeface = getTypeface(context, targetFont) } } }
第二步:修改自定义TextView,支持自动适配与文本变化监听
class TextViewFont : androidx.appcompat.widget.AppCompatTextView { constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) { init(context) } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { init(context) } constructor(context: Context) : super(context) { init(context) } private fun init(context: Context) { // 初始化时设置对应字体 FontManager.applyIconFont(this, context) // 监听文本变化,动态更新字体 addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { FontManager.applyIconFont(this@TextViewFont, context) } }) } }
可选优化:添加自定义属性手动指定字体风格
如果需要在布局中手动指定字体风格,可以在res/values/attrs.xml中添加自定义属性:
<declare-styleable name="TextViewFont"> <attr name="faFontStyle" format="enum"> <enum name="regular" value="0"/> <enum name="solid" value="1"/> <enum name="brand" value="2"/> </attr> </declare-styleable>
然后在自定义TextView的init方法中读取属性:
private fun init(context: Context, attrs: AttributeSet? = null) { var fontPath = FontManager.FA_SOLID // 默认实心风格 attrs?.let { val typedArray = context.obtainStyledAttributes(it, R.styleable.TextViewFont) val style = typedArray.getInt(R.styleable.TextViewFont_faFontStyle, 1) fontPath = when(style) { 0 -> FontManager.FA_REGULAR 1 -> FontManager.FA_SOLID 2 -> FontManager.FA_BRAND else -> FontManager.FA_SOLID } typedArray.recycle() } this.typeface = FontManager.getTypeface(context, fontPath) }
布局中使用示例:
<com.yourpackage.TextViewFont android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/fa_github" app:faFontStyle="brand"/>
内容的提问来源于stack exchange,提问作者WinterChilly




