阅读 1430

玩转安卓字体

起因

最近公司有个需求,需要做 AppWidget ,内心其实是拒绝的,因为这个玩意儿特别难用,而且限制重重,但没办法,也不能不做,那就开始吧。

本来以为挺简单的东西,一个列表展示数据,然后再展示一些基本数据,两天搞定,然后拿给 UI 去看,下面是和UI的对话。

UI:你照着蓝湖做了嘛?

我:有啥问题吗?(很纳闷。。。我就是照着蓝湖做的啊!)

UI:你看你这个时间的字体和我图上的不一样啊!

我:额。。。行吧,我回去想想办法,你把字体发给我吧(内心一万只草泥马走过。。。)

原生字体

很久没搞过字体了,安卓系统一共为我们预制了四种字体,来看下吧:

  1. Normal(普通字体,系统默认使用的字体)
  2. sans(非衬线字体)
  3. serif(衬线字体)
  4. monospace(等宽字体)

来看个例子吧:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Normal"
        android:textColor="#000"
        android:textSize="30sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:fontFamily="sans-serif"
        android:text="Sans"
        android:textColor="#000"
        android:textSize="30sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:fontFamily="serif"
        android:text="Serif"
        android:textColor="#000"
        android:textSize="30sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:fontFamily="monospace"
        android:text="Monospace"
        android:textColor="#000"
        android:textSize="30sp" />

</LinearLayout>
复制代码

上面例子很简单,一个线性布局包裹着上面描述的系统预制的四种字体,来看下效果图吧:

image.png

其实并不是只能像上面这样来进行使用,上面的四种还可以进行相互组合,也可以有不同的效果,大家可以自己试试:

image.png

字体并不是只能在布局文件中进行修改,在代码中同样可以进行修改:

//设置字体样式  
mainText.typeface = Typeface.SANS_SERIF
mainText.typeface = Typeface.SERIF
复制代码

如果没有什么特殊要求的话,上面的这几种字体基本就能满足大部分的开发需求了,而且还都可以对字体进行加粗和斜体,就更能满足了。

使用三方字体

但UI并不认为安卓预制的几种字体好看,就想弄点不一样的字体😂,那也没办法,就来看看怎么设置吧。

引入字体

既然想使用三方字体,那第一步肯定是要引入下三方字体文件,字体文件后缀为 .ttf,需要将字体文件放到assets->fonts文件夹中,项目中没有这个文件夹不要紧,自己新建一个即可。

使用

使用很简单,通过AssetsManager就能获取到字体文件,然后直接通过setTypeFace方法将字体设置下即可:

//从asset 读取字体 根据路径得到Typeface  
val tf = Typeface.createFromAsset(assets, "fonts/你的字体名称.ttf")
//设置字体  
mainText.typeface = tf
复制代码

问题

至此为止,上面的内容就是百度安卓字体能出来的内容,但是!!!没法用啊,文章开头就说到了,我现在做的是 AppWidget 啊,限制非常多,只能通过 RemoteView 的一些固定方法来设置控件的值,但 RemoteView 中并没有可以设置字体的方法,这该咋办呢???

百度了半天也没有找到结果,就想着能不能在 Application 中通过反射将 TextView 的字体中其中一个的默认字体给修改成我想要的字体,然后通过设置主题的方法给 AppWidget 中的 TextView 进行设置以来达到修改字体的结果。

先来写下 Application 中的字体替换代码:

class App : Application() {

    override fun onCreate() {
        super.onCreate()
        updateFont()
    }

    private fun updateFont() {
        val regular = Typeface.createFromAsset(
            assets,
            "fonts/你的字体名称.ttf"
        )
        replaceFont(regular)
    }


    @SuppressLint("DiscouragedPrivateApi")
    private fun replaceFont(newTypeface: Typeface) {
        val newMap: MutableMap<String?, Typeface> = HashMap()
        newMap["MONOSPACE"] = newTypeface
        try {
            val staticField = Typeface::class.java
                .getDeclaredField("sSystemFontMap")
            staticField.isAccessible = true
            staticField[null] = newMap
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

}
复制代码

下面来在主题中设置下:

<!-- 字体 theme. -->
<style name="FontAppTheme" parent="Theme.AppCompat">
    <item name="android:typeface">monospace</item>
</style>
复制代码

之后就可以在 TextView 中进行设置了:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:text="12:34"
    android:textColor="#000"
    android:textSize="30sp"
    android:theme="@style/FontAppTheme" />
复制代码

解决方案

上面的这种方法太麻烦,而且还使用了反射,太不友好了。就想着去看看官方文档吧,没准有什么好用的方法呢。

果然。。。。进入官方文档的第一句话就给我整笑了。。。

image.png

What?只需要像放图片一样在 res 中建一个 font 文件夹,然后将字体放进去,就可以像使用图片一样来使用字体了???

那我搞上面一堆干啥??

嗯。。。。遇到问题还是尽量少百度,多看官方文档吧。。

而且动态设置字体的时候也没必要像之前那样通过 AssetsManager 来获取字体了,只需要通过 Resources 就可以获取到了:

val tf = resources.getFont(R.font.myfont)
mainText.typeface = tf
复制代码

这是字体官方文档的地址:developer.android.google.cn/guide/topic…

总结

哎,其实很简单的一个东西,而且在 Android 8.0 的时候就已经实现的东西,现在马上都 Android 12 了我竟然都不知道,惭愧啊!!!

好了,就这样吧,大家以后遇到问题还是多看文档吧。。。千万不要学我。

文章分类
Android
文章标签