返回顶部
首页 > 资讯 > 移动开发 >Android字体相关知识总结
  • 173
分享到

Android字体相关知识总结

2024-04-02 19:04:59 173人浏览 泡泡鱼
摘要

目录一、Android 默认字体介绍二、textStyle三、typeface四、fontFamily 五、textStyle,typeface,fontFamily 三者

一、Android 默认字体介绍

1、Android 系统默认使用的是一款叫做 Roboto 的字体,这也是 Google 推荐使用的一款字体 传送门。它提供了多种字体形式的选择,例如:粗体,斜体等等。

2、在 Android 中,我们一般会直接或间接的通过 TextView 控件去承载字体的显示,因为关于 Android 提供的承载字体显示的控件都会直接或间接继承 TextView,例如:EditText,Button 等等,下面给出一张 TextView 继承图:

3、TextView 中有三个属性可以设置字体的显示:

1)、textStyle

2)、typeface

3)、fontFamily

下面我们重点介绍下这三个属性

二、textStyle

textStyle 主要用来设置字体的样式,我们看下它在 TextView 的自定义属性中的一个体现:


//TextView 的自定义属性 textStyle
<attr name="textStyle">
    <flag name="nORMal" value="0" />
    <flag name="bold" value="1" />
    <flag name="italic" value="2" />
</attr>

从上述自定义属性中我们可以知道:

1、textStyle 主要有 3 种样式:

  • normal:默认字体
  • bold:粗体
  • italic:斜体

2、textStyle 是用 flag 来承载的,flag 表示的值可以做或运算,也就是说我们可以设置多种字体样式进行叠加

接下来我们在 xml 中设置一下,如下图:

可以看到,我们给 TextView 的 textStyle 属性设置了粗体和斜体两种样式叠加,右边可以看到预览效果

同样我们也可以在代码中对其进行设置,但是在代码中设置字体样式只能设置一种,不能叠加:


mTextView.setTypeface(null, Typeface.BOLD)

三、typeface

typeface 主要用于设置 TextView 的字体,我们看下它在 TextView 的自定义属性中的一个体现:


//TextView 的自定义属性 typeface
<attr name="typeface">
    <enum name="normal" value="0" />
    <enum name="sans" value="1" />
    <enum name="serif" value="2" />
    <enum name="monospace" value="3" />
</attr>

从上述自定义属性中我们可以知道:

1、typeface 提供了 4 种字体:

  • noraml:普通字体,系统默认使用的字体
  • sans:非衬线字体
  • serif:衬线字体
  • monospace:等宽字体

2、typeface 是用 enum 来承载的,enum 表示枚举类型,每次只能选择一个,因此我们每次只能设置一种字体,不能叠加

接下来我们在 xml 中设置一下,如下图:

简单介绍这几种字体的区别:

serif (衬线字体):在字的笔划开始及结束的地方有额外的装饰,而且笔划的粗细会因直横的不同而有不同相

sans (非衬线字体):没有 serif 字体这些额外的装饰,和 noraml 字体是一样的

monospace (等宽字体):限制每个字符的宽度,让它们达到一个等宽的效果

同样我们也可以在代码中进行设置:


mTv.setTypeface(Typeface.SERIF)

四、fontFamily 

fontFamily 相当于是加强版的 typeface,它表示 android 系统支持的一系列字体,每个字体都有一个别名,我们通过别名就能设置这种字体,看下它在 TextView 的自定义属性中的一个体现:


//TextView 的自定义属性 fontFamily
<attr name="fontFamily" format="string" />

从上述自定义属性中我们可以知道:

fontFamily 接收的是一个 String 类型的值,也就是我们可以通过字体别名设置这种字体,如下图:

可以看到,它细致的区分了每个系列字体的样式,同样我们在 xml 中对它进行一个设置:

我们在代码中在对他进行一个设置:


mTv.setTypeface(Typeface.create("sans-serif-medium",Typeface.NORMAL))

值的注意的是:fontFamily 设置的某些字体有兼容性问题,如我上面设置的 sans-serif-medium 字体,它在 Android 系统版本大于等于 21 才会生效,如果小于 21 ,则会使用默认字体,因此我们在使用 fontFamily 属性时,需要注意这个问题

到这里,我们就把影响 Android 字体的 3 个属性给讲完了,但是我心里有个疑问🤔️ ?假设我这三个属性同时设置,会一起生效吗?

带着这个问题,我们探索一下源码

五、textStyle,typeface,fontFamily 三者关系分析

TextView 在我们使用它之前需进行一个初始化,最终会调用它参数最多的那个构造方法:


public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  	//省略成吨代码.....
  	//读取设置的属性
  	readTextAppearance(context, appearance, attributes, false );
  	//设置字体
  	applyTextAppearance(attributes);
 }

private void applyTextAppearance(TextAppearanceAttributes attributes) {
   	//省略成吨代码.....
  	setTypefaceFromAttrs(attributes.mFontTypeface, attributes.mFontFamily,
                attributes.mTypefaceIndex, attributes.mTextStyle, attributes.mFontWeight);
}

上面这条调用链,首先会读取 TextView 设置的相关属性,我们看下与字体相关的几个:


private void readTextAppearance(Context context, TypedArray appearance,
            TextAppearanceAttributes attributes, boolean styleArray) {
  	//...
  	switch (index) {
 	    case com.android.internal.R.styleable.TextAppearance_typeface:
                attributes.mTypefaceIndex = appearance.getInt(attr, attributes.mTypefaceIndex);
                if (attributes.mTypefaceIndex != -1 && !attributes.mFontFamilyExplicit) {
                    attributes.mFontFamily = null;
                }
                break;
            case com.android.internal.R.styleable.TextAppearance_fontFamily:
                if (!context.isRestricted() && context.canLoadUnsafeResources()) {
                    try {
                        attributes.mFontTypeface = appearance.getFont(attr);
                    } catch (UnsupportedOperationException | Resources.NotFoundException e) {
                        // Expected if it is not a font resource.
                    }
                }
                if (attributes.mFontTypeface == null) {
                    attributes.mFontFamily = appearance.getString(attr);
                }
                attributes.mFontFamilyExplicit = true;
                break;
            case com.android.internal.R.styleable.TextAppearance_textStyle:
                attributes.mTextStyle = appearance.getInt(attr, attributes.mTextStyle);
                break;
            //...
   	    default:
     }
}

从上述代码中我们可以看到:

1、当我们设置 typeface 属性时,会将对应的属性值赋给 mTypefaceIndex ,并把 mFontFamily 置为 null

2、当我们设置 fontFamily 属性时,首先会通过 appearance.getFont() 方法去获取字体文件,如果能获取到,则赋值给 mFontTypeface,如果获取不到,则通过 appearance.getString() 方法取获取当前字体别名并赋值给 mFontFamily

注意:当我们给 fontFamily 设置了一些第三方字体,那么此时 appearance.getFont() 方法就获取不到字体

3、当我们设置 textStyle 属性时,会将获取的属性值赋给 mTextStyle

上述方法走完了,会调 setTypefaceFromAttrs() 方法,这个方法就是最终 TextView 设置字体的方法,我们来解析下这个方法:


private void setTypefaceFromAttrs(@Nullable Typeface typeface, @Nullable String familyName,
            @XMLTypefaceAttr int typefaceIndex, @Typeface.Style int style,
            @IntRange(from = -1, to = FontStyle.FONT_WEIGHT_MAX) int weight) {
    if (typeface == null && familyName != null) {
        // Lookup normal Typeface from system font map.
        final Typeface normalTypeface = Typeface.create(familyName, Typeface.NORMAL);
        resolveStyleAndSetTypeface(normalTypeface, style, weight);
    } else if (typeface != null) {
        resolveStyleAndSetTypeface(typeface, style, weight);
    } else {  // both typeface and familyName is null.
        switch (typefaceIndex) {
            case SANS:
                resolveStyleAndSetTypeface(Typeface.SANS_SERIF, style, weight);
                break;
            case SERIF:
                resolveStyleAndSetTypeface(Typeface.SERIF, style, weight);
                break;
            case MONOSPACE:
                resolveStyleAndSetTypeface(Typeface.MONOSPACE, style, weight);
                break;
            case DEFAULT_TYPEFACE:
            default:
                resolveStyleAndSetTypeface(null, style, weight);
                break;
        }
    }
}

上述代码步骤:

1、当 typeface 为空并且 familyName 不为空时,取 familyName 的字体

2、当 typeface 不为空并且 familyName 为空时,取 typeface 的字体

3、当 typeface 和 familyName 都为空,则根据 typefaceIndex 的值取相应的字体

4、typeface ,familyName 和 typefaceIndex 在我们分析的 readTextAppearance 方法会被赋值

5、resolveStyleAndSetTypefce 方法会进行字体和字体样式的设置

6、style 是在 readTextAppearance 方法中赋值的,他和设置字体并不冲突

好,现在代码分析的差不多了,我们再来看下上面那个疑问?我们使用假设法来进行推导:

假设在 Xml 中, typeface,familyName 和 textStyle 我都设置了,那么根据上面分析:

1、textStyle 肯定会生效

2、当设置了 typeface 属性,typefaceIndex 会被赋值,同时 familyName 会置为空

3、当设置了 familyName 属性,分情况:1、如果设置的是系统字体,typeface 会被赋值,familyName 还是为空。2、如果设置的是第三方字体,typeface 为空,familyName 被赋值

因此,当我们设置了这个三个属性,typeface 和 familyName 总有一个不会为空,因此不会走第三个条件体,那么 typeface 设置的属性就不会生效了,而剩下的两个属性都能够生效

最后对这三个属性做一个总结:

1、fontFamily、typeface 属性用于字体设置,如果都设置了,优先使用 fontFamily 属性,typeface 属性不会生效

2、textStyle 用于字体样式设置,与字体设置不会产生冲突

上面这段源码分析可能有点绕,如果有不清楚的地方,欢迎评论区给我留言提问

六、TextView 设置字体属性源码分析

通过上面源码的分析,我们清楚了 fontFamily,typeface 和 textStyle 这三者的关系。接下来我们研究一下,我们设置的这些属性是怎么实现这些效果的呢?又到了源码分析环节😂,可能会有点枯燥,但是如果你能够认真看完,一定会收获很多,干就完了

我们上面用 Xml 或代码设置的字体属性,最终都会走到 TextView 的 setTypeface 重载方法:


//重载方法一
public void setTypeface(@Nullable Typeface tf) {
    if (mTextPaint.getTypeface() != tf) {
      	//通过 mTextPaint 设置字体
        mTextPaint.setTypeface(tf);
      
      	//刷新重绘
        if (mLayout != null) {
            nullLayouts();
            requestLayout();
            invalidate();
        }
    }
}

//重载方法二
public void setTypeface(@Nullable Typeface tf, @Typeface.Style int style) {
  if (style > 0) {
        if (tf == null) {
            tf = Typeface.defaultFromStyle(style);
        } else {
            tf = Typeface.create(tf, style);
        }
	//调用重载方法一,设置字体
        setTypeface(tf);
      	//经过一些算法
        int typefaceStyle = tf != null ? tf.getStyle() : 0;
        int need = style & ~typefaceStyle;
      	//打开画笔的粗体和斜体
        mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
        mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
    } else {
        mTextPaint.setFakeBoldText(false);
        mTextPaint.setTextSkewX(0);
        setTypeface(tf);
    }
}

分析下上述代码:

重载方法一:

TextView 设置字体实际上就是操作 mTextPaint,mTextPaint 是 TextPaint 的类对象,继承自 Paint 即画笔,因此我们设置的字体实际上会通过调用画笔的方法来进行绘制

重载方法二:

相对于重载方法一,法二多传递了一个 textStyle 参数,主要用来标记粗体和斜体的:

1)、如果设置了 textStyle ,进入第一个条件体,分情况:1、如果传进来的 tf 为 null ,则会根据传入的 style 去获取 Typeface 字体,2、如果不为 null ,则会根据传入的 tf 和 style 去获取 Typeface 字体。设置好字体后,接下来还会打开画笔的粗体和斜体设置

2)、如果没有设置 textStyle,则只会设置字体,并把画笔的粗斜体设置置为 false 和 0

从上述分析我们可以得知:TextView 设置字体和字体样式最终都是通过画笔来完成的

七、总结

本篇文章主要讲了:

1、Android 字体大概的一个介绍

2、关于影响 Android 字体显示的三个属性

3、textStyle,typeface,fontFamily 三者的一个关系

4、设置的这三个属性是怎么实现这些效果的?

可能大家会问,你上面那个需求还没讲怎么就要结束了呢?我上面那个需求,以今天所讲的知识可能还实现不了,别着急,关于 Android 字体我准备写个系列,因为内容实在是太多了。这个系列文章不会让大家等太久,因为在参加掘金 6 月更文挑战,准备爆肝 9 篇😄

好了,本篇文章到这里就结束了,如果有任何问题,欢迎给我留言,我们评论区一起讨论🤝

以上就是Android字体相关知识总结的详细内容,更多关于Android字体的资料请关注编程网其它相关文章!

--结束END--

本文标题: Android字体相关知识总结

本文链接: https://lsjlt.com/news/128446.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android字体相关知识总结
    目录一、Android 默认字体介绍二、textStyle三、typeface四、fontFamily 五、textStyle,typeface,fontFamily 三者...
    99+
    2024-04-02
  • Android Insets相关知识总结
    目录什么是Insets?Insets相关类InsetsStateInsetsStateControllerInsetsSourceInsetsSourceConsumer(ImeIn...
    99+
    2024-04-02
  • 总结HTML相关知识
    这篇文章主要介绍“总结HTML相关知识”,在日常操作中,相信很多人在总结HTML相关知识问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”总结HTML相关知识”的疑惑有所帮助!接...
    99+
    2024-04-02
  • Java集合的总体框架相关知识总结
    目录一、集合概述二、集合在开发中的应用三、集合存储的数据四、集合的包五、集合的两大类一、集合概述 数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其它的数据。 二、集合在开发...
    99+
    2024-04-02
  • Spring Cache相关知识总结
    简介  Spring 从 3.1 开始定义了 org.springframework.cache.Cache 和 org.springframework.cache.Cac...
    99+
    2024-04-02
  • HTML相关知识点总结
    目录简介HTML文档和网页的关系呢?HTML的标签样子?HTML基本概念标签元素属性注释编码规则HTML常用元素标题段落链接跳转页面:跳转锚点图片列表有序列表无序列表定义列表表格块表...
    99+
    2024-04-02
  • MySQL 日志相关知识总结
    数据库中用于存储数据的文件称为data file,日志文件称为log file。此外,如果每次读写都是直接访问磁盘,性能很差,所以数据库是有缓存的,数据缓存是data buffer,日志缓存log buffer。 s...
    99+
    2022-05-21
    MySQL 日志
  • MySQL 锁的相关知识总结
    MySQL中的锁 锁是为了解决并发环境下资源竞争的手段,其中乐观并发控制,悲观并发控制和多版本并发控制是数据库并发控制主要采用的技术手段(具体可见我之前的文章),而MySQL中的锁就是其中的悲观并发控制。 MySQ...
    99+
    2022-05-14
    MySQL
  • MySQL权限相关知识总结
    本篇内容主要讲解“MySQL权限相关知识总结”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL权限相关知识总结”吧! 一.权限表 mysql中的3个权...
    99+
    2024-04-02
  • MySQL 慢日志相关知识总结
    目录  1.慢日志简介  2.慢日志实战  1.慢日志简介 慢日志全称为慢查询日志(Slow Query Log),主要用来记录在 MySQL 中执行时间超过指定时间的 SQL 语句。通...
    99+
    2022-05-22
    MySQL 慢日志
  • java类加载相关知识总结
    目录类加载器代码示例ClassLoader 中的两个方法类加载器 类加载器作用 负责将.class文件(存储的物理文件)加载到内存中 类加载器过程 加载:通过...
    99+
    2024-04-02
  • 总结Python变量的相关知识
    一、变量的定义 程序中,数据都是临时存储在内存中,为了更快速的查找或使用这个数据,通常我们把这个数据在内存中存储之后,给整个数据定义一个名称,这个名称就是变量。 变量就是在存储数据...
    99+
    2024-04-02
  • Redis 事务知识点相关总结
    目录01 事务简介02 命令错误导致的事务提交失败,所有命令都不执行03 运行时错误导致数据错误04 丢弃事务05 watch命令06 总结Redis中的事务介绍  &nb...
    99+
    2024-04-02
  • Java与Mysql锁相关知识总结
    目录锁的定义锁的实现JVM中的锁synchronizedReentrantLockMysql 锁共享锁(S) 与排它锁(X)作用范围意向锁作用范围记录锁间隙锁Next-Key Loc...
    99+
    2023-05-16
    Java与MySQL中的锁 Java中使用Mysql数据库实现锁 java mysql锁实现
  • Mysql相关知识总结-持续更新~~~
         2019-12-11对varchar类型排序问题的解决 在mysql默认order by 只对数字与日期类型可以排序,但对于varchar字符型类型排序好像没有用了,下面我来给各位同学介绍varchar类型排序问题如何解决。 现象...
    99+
    2019-06-22
    Mysql相关知识总结-持续更新~~~
  • Pyhton模块和包相关知识总结
    目录一、模块二、模块的搜索顺序三、使模块下方的测试代码在导入时不会执行四、包五、发布模块六、安装模块七、卸载模块八、pip 安装第三方模块一、模块 每一个以扩展名 py 结尾额 Py...
    99+
    2024-04-02
  • SpringMVC数据输出相关知识总结
    一、数据输出 SpringMVC将数据携带给页面的储存工具,有三种,map,ModelMap,model,它们在底层实质还是使用到了BindingAwareModelMap,对数据进...
    99+
    2024-04-02
  • Java并发容器相关知识总结
    目录一、并发容器1.1 JDK 提供的并发容器总结1.2 ConcurrentHashMap1.3 CopyOnWriteArrayList1.3.1 CopyOnWriteArra...
    99+
    2024-04-02
  • SpringMVC 参数绑定相关知识总结
    目录1. 简单参数绑定2. 对象参数绑定3. 参数绑定解析总结请求进入DispatcherServlet的doDispatch后,获取HandlerMethod。然后根据Handle...
    99+
    2024-04-02
  • JavaScript数据类型相关知识总结
    本篇内容介绍了“JavaScript数据类型相关知识总结”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!js...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作