起因
最近公司有个需求,需要做 Widget
,内心其实是拒绝的,因为这个玩意儿特别难用,而且限制重重,但没办法,也不能不做,那就开始吧。
本来以为挺简单的东西,一个列表展示数据,然后再展示一些基本数据,两天搞定,然后拿给 UI 去看,下面是和UI的对话。
UI:你照着蓝湖做了嘛?
我:有啥问题吗?(很纳闷。。。我就是照着蓝湖做的啊!)
UI:你看你这个时间的字体和我图上的不一样啊!
我:额。。。行吧,我回去想想办法,你把字体发给我吧(内心一万只草泥马走过。。。)
原生字体
很久没搞过字体了,安卓系统一共为我们预制了四种字体,来看下吧:
- Normal(普通字体,系统默认使用的字体)
- sans(非衬线字体)
- serif(衬线字体)
- 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"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="10dp"android:text="Normal"android:textColor="#000"android:textSize="30sp" /><TextViewandroid: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" /><TextViewandroid: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" /><TextViewandroid: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>
上面例子很简单,一个线性布局包裹着上面描述的系统预制的四种字体,来看下效果图吧:
其实并不是只能像上面这样来进行使用,上面的四种还可以进行相互组合,也可以有不同的效果,大家可以自己试试:
字体并不是只能在布局文件中进行修改,在代码中同样可以进行修改:
//设置字体样式
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"] = newTypefacetry {val staticField = Typeface::class.java.getDeclaredField("sSystemFontMap")staticField.isAccessible = truestaticField[null] = newMap} catch (e: Exception) {e.printStackTrace()}}}
下面来在主题中设置下:
<!-- 字体 theme. -->
<style name="FontAppTheme" parent="Theme.AppCompat"><item name="android:typeface">monospace</item>
</style>
之后就可以在 TextView
中进行设置了:
<TextViewandroid: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" />
解决方案
上面的这种方法太麻烦,而且还使用了反射,太不友好了。就想着去看看官方文档吧,没准有什么好用的方法呢。
果然。。。。进入官方文档的第一句话就给我整笑了。。。
What?只需要像放图片一样在 res 中建一个 font 文件夹,然后将字体放进去,就可以像使用图片一样来使用字体了???
那我搞上面一堆干啥??
嗯。。。。遇到问题还是尽量少百度,多看官方文档吧。。
而且动态设置字体的时候也没必要像之前那样通过 AssetsManager
来获取字体了,只需要通过 Resources
就可以获取到了:
val tf = resources.getFont(R.font.myfont)
mainText.typeface = tf
这是字体官方文档的地址:https://developer.android.google.cn/guide/topics/ui/look-and-feel/fonts-in-xml
总结
哎,其实很简单的一个东西,而且在 Android 8.0 的时候就已经实现的东西,现在马上都 Android 12 了我竟然都不知道,惭愧啊!!!
好了,就这样吧,大家以后遇到问题还是多看文档吧。。。千万不要学我。