Android进阶之路 - 字体加粗,定制化字体粗度

在客户端中不论是PC端,还是移动端主要价值之一就体现在用户交互方面,也就是用户体验了,接下来讲的是很常见的字体加粗问题

UI大找茬

  • 深入浅出字体、字体库
  • TextView文本渐变
  • 字体阴影、文字阴影
  • 字体加粗 - 定制化字体粗度

在开发中经常会遇到设计说某个文本字体粗度不对,需要重一点,或者轻一点,这时候当系统控件原属性不满足需求时,就需要我们定制化处理一下

    • 基础讲解
    • 系统自带 - 原始版(粗度固定,无扩展)
    • 自定义控件 - 基础版(扩展不足,基本够用)
      • 优化前
      • 优化后
    • 使用方式
      • 静态设置
      • 动态设置
    • 自定义控件 - 进阶版(推荐:可自行扩展,定制化高)
      • 仅支持动态设置
      • 支持动态、静态设置
        • 静态设置
        • 动态设置

虽然看起来写了不少,但其实核心只在于获取当前控件的 Paint(画笔)后重新设置strokeWidth、style属性 ,然后重新绘制即可!

tip:差点忘记说了,如果通过该篇未满足你的诉求,你可以看一下设计是否使用了字体库,一般字体库也会提供常规字体和加粗字体,关于字体库方面的知识,可以直接前往 深入浅出字体、字体库

基础讲解

设计比较喜欢拿 Android 与 IOS 做对比,所以经常会遇到一些 IOS 分分钟解决的问题,Android 却需要花多倍的时间来处理,以前经常会遇到 1 IOS = 1.5||2 Android 的场景,现在这环境可能比较这样的场景也比较少咯

关于字体粗度的实际设置,主要是在体现其 字重(字体粗细),因字重等级不同,带来的效果也有所不同

Andoird 提供的字体粗度主要有俩种

  • normal 默认正常字体(0)
  • bold 加粗字体(1)

相对于Android 提供的 regular-400bold-700 两种字重(设置600以下均以400字重效果来显示;设置700才会显示出加粗文字)- 源码中常以 0 - 1设置字重 ;iOS系统原生字体字重等级全面,从100-600都有,效果也更全一些,网上找了一个对比图如下

在这里插入图片描述

由于 Andoird 的开源性,在国内有着众多厂商,不同厂商有时候也会设计自已品牌的系统字体包,所以即便是相同的代码,也可能在不同的安卓手机上呈现的效果也可能不相同,因此我们往往需要通过一些自定义控件来尽量保持效果的一致性!


系统自带 - 原始版(粗度固定,无扩展)

AndroidTextViewEditText 提供了 textStyle 属性用于设置字体粗度

  <TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="字体粗度"android:textStyle="bold" />

实现效果
在这里插入图片描述
在这里插入图片描述

关于 textStyle 属性值,主要提供了以下三种类型

  • normal 默认正常字体
  • bold 加粗字体
  • italic 斜体
<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="MediumTextView"><attr name="mediumState" format="boolean" /></declare-styleable></resources>

自定义控件 - 基础版(扩展不足,基本够用)

首先在 attr/attrs 添加自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="MediumTextView"><attr name="mediumState" format="boolean" /></declare-styleable>
</resources>

实现效果

在这里插入图片描述

Tip:以下俩种方式均可正常使用,建议使用优化后的减少无效逻辑

优化前

package com.example.boldtextimport android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.support.v7.widget.AppCompatTextView
import android.util.AttributeSetclass MediumOldTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AppCompatTextView(context, attrs, defStyleAttr) {private var mediumState: Boolean = falseinit {val array = context.obtainStyledAttributes(attrs, R.styleable.MediumTextView)mediumState = array.getBoolean(R.styleable.MediumTextView_mediumState, false)array.recycle()}override fun onDraw(canvas: Canvas?) {if (mediumState) {val strokeWidth = paint.strokeWidthval style = paint.stylepaint.strokeWidth = 0.6fpaint.style = Paint.Style.FILL_AND_STROKEsuper.onDraw(canvas)paint.strokeWidth = strokeWidthpaint.style = style} else {super.onDraw(canvas)}}fun setMediumState(mediumState: Boolean) {this.mediumState = mediumStaterequestLayout()}}

优化后

去除一些无用逻辑、代码

package com.example.boldtextimport android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.support.v7.widget.AppCompatTextView
import android.util.AttributeSetclass MediumTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AppCompatTextView(context, attrs, defStyleAttr) {private var mediumState: Boolean = falseinit {val array = context.obtainStyledAttributes(attrs, R.styleable.MediumTextView)mediumState = array.getBoolean(R.styleable.MediumTextView_mediumState, false)array.recycle()}override fun onDraw(canvas: Canvas?) {if (mediumState) {//可通过设置该数值改变加粗字重paint.strokeWidth = 0.6fpaint.style = Paint.Style.FILL_AND_STROKE}super.onDraw(canvas)}fun setMediumText(mediumText: Boolean) {this.mediumState = mediumTextrequestLayout()
//        postInvalidate()}}

使用方式

静态为 xml 设置,动态为代码设置

静态设置

<com.example.boldtext.MediumTextViewandroid:id="@+id/medium_view"android:layout_width="match_parent"android:layout_height="45dp"android:gravity="center"android:text="加粗字体"app:mediumState="true" />

动态设置

package com.example.boldtextimport android.support.v7.app.AppCompatActivity
import android.os.Bundleclass MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val mediumView = findViewById<MediumTextView>(R.id.medium_view)//设置加粗mediumView.setMediumState(true)}
}

自定义控件 - 进阶版(推荐:可自行扩展,定制化高)

实现效果

在这里插入图片描述

仅支持动态设置

Tip:假设别的组件也有字体加粗的需求,可以尝试继承该组件

创建 - 自定义组件

package com.example.boldtextimport android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.support.v7.widget.AppCompatTextView
import android.util.AttributeSetopen class TypefaceTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :AppCompatTextView(context, attrs, defStyleAttr) {private var mTypefaceScale: Float = 0.0fenum class TypefaceScale {MEDIUM, MEDIUM_SMALL, DEFAULT,}override fun onDraw(canvas: Canvas?) {if (mTypefaceScale == 0f) {return super.onDraw(canvas)}val strokeWidth = paint.strokeWidthval style = paint.stylepaint.strokeWidth = mTypefaceScalepaint.style = Paint.Style.FILL_AND_STROKEsuper.onDraw(canvas)paint.strokeWidth = strokeWidthpaint.style = style}fun setTypefaceScale(scale: TypefaceScale = TypefaceScale.DEFAULT) {mTypefaceScale = when (scale) {TypefaceScale.DEFAULT -> 0.0fTypefaceScale.MEDIUM_SMALL -> 0.6fTypefaceScale.MEDIUM -> 1.1f}postInvalidate()}}

使用方式

package com.example.boldtextimport android.support.v7.app.AppCompatActivity
import android.os.Bundleclass MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val typefaceView = findViewById<TypefaceTextView>(R.id.typeface_view)//设置加粗typefaceView.setTypefaceScale(TypefaceTextView.TypefaceScale.MEDIUM_SMALL)}
}

控件引入

    <com.example.boldtext.TypefaceTextViewandroid:id="@+id/typeface_view"android:layout_width="match_parent"android:layout_height="45dp"android:gravity="center"android:text="TypefaceTextView 加粗字体" />

扩展:因为我们用的是 splitties 三方的一个布局组件,所以分享、记录一些扩展函数,逐步分析、学习

布局方式

   add(lParams(), typefaceTextView {gravity = gravityEndtypefaceScale = TypefaceScale.MEDIUM_SMALLtextSize = 14ftextColor = "#333333".toColorInt()})

add函数 将子布局添加到对应ViewGroup中

import android.view.View
import android.view.ViewGroupinline fun <V : View> ViewGroup.add(lp: ViewGroup.LayoutParams, view: V): V = view.also { addView(it, lp) }

splitties - lParams 函数

inline fun LinearLayout.lParams(width: Int = wrapContent,height: Int = wrapContent,initParams: LinearLayout.LayoutParams.() -> Unit = {}
): LinearLayout.LayoutParams {contract { callsInPlace(initParams, InvocationKind.EXACTLY_ONCE) }return LinearLayout.LayoutParams(width, height).apply(initParams)
}inline fun LinearLayout.lParams(width: Int = wrapContent,height: Int = wrapContent,gravity: Int = -1,weight: Float = 0f,initParams: LinearLayout.LayoutParams.() -> Unit = {}
): LinearLayout.LayoutParams {contract { callsInPlace(initParams, InvocationKind.EXACTLY_ONCE) }return LinearLayout.LayoutParams(width, height).also {it.gravity = gravityit.weight = weight}.apply(initParams)
}

View - typefaceTextView 函数

// TypefaceTextView 防苹果系统的字体加粗------------------------------------------------------------------
inline fun Context.typefaceTextView(@IdRes id: Int = View.NO_ID,@StyleRes theme: Int = NO_THEME,initView: TypefaceTextView.() -> Unit = {}
): TypefaceTextView {return view(::TypefaceTextView, id, theme, initView)
}inline fun View.typefaceTextView(@IdRes id: Int = View.NO_ID,@StyleRes theme: Int = NO_THEME,initView: TypefaceTextView.() -> Unit = {}
): TypefaceTextView {return context.typefaceTextView(id, theme, initView)
}inline fun Ui.typefaceTextView(@IdRes id: Int = View.NO_ID,@StyleRes theme: Int = NO_THEME,initView: TypefaceTextView.() -> Unit = {}
): TypefaceTextView {return ctx.typefaceTextView(id, theme, initView)
}
// -------------------------------------------------------------------------------------------------------

typefaceTextView - typefaceScale 加粗类型函数

enum class TypefaceScale {
//    MEDIUM,MEDIUM_SMALL,DEFAULT,
}var TypefaceTextView.typefaceScale: TypefaceScale@Deprecated(NO_GETTER, level = DeprecationLevel.HIDDEN) get() = noGetterset(value) {val scale = when (value) {
//            TypefaceScale.MEDIUM -> TypefaceTextView.TypefaceScale.MEDIUMTypefaceScale.MEDIUM_SMALL -> TypefaceTextView.TypefaceScale.MEDIUM_SMALLTypefaceScale.DEFAULT -> TypefaceTextView.TypefaceScale.DEFAULT}setTypefaceScale(scale)}

支持动态、静态设置

为了方便直接在 xml 中使字体加粗,需要在控件上引入自定义属性,故需添加以下属性

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="TypefaceTextView"><attr name="fontScale" format="enum"><enum name="normal" value="0" /><enum name="medium" value="1" /><enum name="bold" value="2" /></attr></declare-styleable>
</resources>

创建 - 自定义组件

package com.example.boldtextimport android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.support.v7.widget.AppCompatTextView
import android.util.AttributeSetclass TypefaceTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :AppCompatTextView(context, attrs, defStyleAttr) {private var mTypefaceScale: Float = 0.0finit {if (attrs != null) {val array = context.obtainStyledAttributes(attrs, R.styleable.TypefaceTextView)val typefaceScale = array.getInt(R.styleable.TypefaceTextView_fontScale, 0)mTypefaceScale = when (typefaceScale) {1 -> 0.6f2 -> 1.1felse -> 0.0f}array.recycle()}}enum class TypefaceScale {MEDIUM, DEFAULT, BOLD}override fun onDraw(canvas: Canvas?) {if (mTypefaceScale == 0f) {return super.onDraw(canvas)}val strokeWidth = paint.strokeWidthval style = paint.stylepaint.strokeWidth = mTypefaceScalepaint.style = Paint.Style.FILL_AND_STROKEsuper.onDraw(canvas)paint.strokeWidth = strokeWidthpaint.style = style}internal fun setTypefaceScale(scale: TypefaceScale = TypefaceScale.DEFAULT) {mTypefaceScale = when (scale) {TypefaceScale.DEFAULT -> 0.0fTypefaceScale.MEDIUM -> 0.6fTypefaceScale.BOLD -> 1.1f}invalidate()}}
静态设置

静态设置 fontScale 属性为枚举类型中的其一

    <com.example.boldtext.TypefaceTextViewandroid:layout_width="match_parent"android:layout_height="45dp"android:gravity="center"app:fontScale="bold"android:text="TypefaceTextView 加粗字体" />
动态设置
package com.example.boldtextimport android.support.v7.app.AppCompatActivity
import android.os.Bundleclass MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val typefaceView = findViewById<TypefaceLTextView>(R.id.typeface_view)//设置加粗typefaceView.setTypefaceScale(TypefaceLTextView.TypefaceScale.MEDIUM)}
}

只能设置我们声明的枚举类型,如果项目需要扩展到更多粗度的话,可以自行增加!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/393833.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DFS之搜索顺序与剪枝

搜索顺序&#xff1a; 1.https://www.acwing.com/problem/content/1119/ 首先&#xff0c;我们考虑一个贪心&#xff1a; 假如说A的倒数K个字符恰好与B的前K个字符重合&#xff0c;那么我们就连接。 也就是说我们一旦匹配就直接相连而不是继续找更长的重合的一段子串。 因…

【学习方法】高效学习因素 ② ( 学习动机 | 内在学习动机 | 外在学习动机 | 外在学习动机的调整方向 | 保护学习兴趣 | 高考竞争分析 )

文章目录 一、高效学习的其它因素 - 学习动机1、学习动机2、内在学习动机3、外在学习动机4、外在学习动机的问题所在5、外在学习动机的调整方向6、保护学习兴趣7、高考竞争分析 上一篇博客 【学习方法】高效学习因素 ① ( 开始学习 | 高效学习因素五大因素 | 高效学习公式 - 学…

unplugin-vue-components 插件配置 忽略 部分目录下的组件自动导入

背景 vue3 项目 为了省略 第三方库ui 组件 全局组件的注册代码&#xff0c;使用了 unplugin-vue-components 插件 原理 组件识别 在编译阶段&#xff0c;unplugin-vue-components 会扫描 Vue 单文件组件&#xff08;.vue 文件&#xff09;的模板部分&#xff0c;识别出所有使…

day31

3.9 信号量集 1> 原理图 信号量集主要完成多个进程之间同步问题 2> 信号量集的API函数接口 1、创建用于生成消息队列的钥匙#include <sys/types.h>#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);功能&#xff1a;通过给定的文件路径…

你也觉得FOTA升级难吗?这份详细教程让你自信升级!

前言&#xff1a; 我经常在各个讨论群里看到有合宙Air780EP的用户说&#xff1a; FOTA远程升级有点难呀~一步错后面就得重新来了&#xff0c;有没有大佬给个教程啊&#xff1f; 用户提需求了&#xff0c;那我们肯定要满足啊&#xff0c;就连夜赶了一篇 在整理这篇文章之前&…

掌握 LINQ:通过示例解释 C# 中强大的 LINQ的集运算

文章目录 集运算符原理实战示例1. Union2. Intersect3. Except4. ExceptWith5. Concat6. Distinct 注意事项总结 在C#中&#xff0c;LINQ&#xff08;Language Integrated Query&#xff09;提供了丰富的集合操作功能&#xff0c;使得对集合数据进行查询、过滤、排序等操作变得…

删除有序数组中的重复项(LeetCode)

题目 给你一个 升序排列 的数组 &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 中唯一元素的个数。 考虑 的唯一元素的数量为 &#xff0c;你需要做以下事情确…

CVE-2023-1313

开启靶场 url访问/install来运行安装 http://eci-2ze0wqx38em0qticuhug.cloudeci1.ichunqiu.com/install/ 得知其用户和密码为admin 登录 查找文件上传位置 上传一句话木马文件 <?php echo phpinfo();eval($_POST[flw]);?> 下载查看上传木马路径 复制路径 /storag…

代理IP如何助力品牌保护?

品牌是企业非常重要的无形资产&#xff0c;代表着一个公司、一个产品或服务的价值、信誉和形象。在竞争激烈的市场中&#xff0c;一个强有力的品牌可以帮助公司吸引更多的客户、提高销售、提高客户满意度和忠诚度&#xff0c;还可以帮助公司建立和维护其声誉、增强其企业形象&a…

单词拆分——LeetCode

139.单词拆分 题目 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用 示例 1&#xff1a; 输入: s &qu…

数据结构实验:树和二叉树(附c++源码:实现树有关算法)

目录 一、实验目的 二、问题分析及数据结构设计 三、算法设计&#xff08;伪代码表示&#xff09; 1. 输入字符序列 创建二叉链表 2. 递归前序遍历 3. 递归中序遍历 4. 递归后序遍历 5. 非递归前序遍历 6. 非递归中序遍历 7. 非递归后序遍历 8. 层次遍历 9. 求二叉…

【AI】关于AI和手机

2011 年至2015 年期间&#xff0c;全球智能手机出货量年增长率均超过两位数&#xff0c;显示出强劲的市场需 求和快速扩张趋势。然而&#xff0c;自2016 年起&#xff0c;全球智能手机用户数量趋于饱和&#xff0c;换机周期也逐 渐变长&#xff0c;市场进入存量替换阶段&#x…

Qt/C++最新地图组件发布/历时半年重构/同时支持各种地图内核/包括百度高德腾讯天地图

一、前言说明 最近花了半年时间&#xff0c;专门重构了整个地图组件&#xff0c;之前写的比较粗糙&#xff0c;有点为了完成功能而做的&#xff0c;没有考虑太多拓展性和易用性。这套地图自检这几年大量的实际项目和用户使用下来&#xff0c;反馈了不少很好的建议和意见&#…

PXE 批量安装Linux系统

目录 一、 实验环境准备 1、一台红帽版本7的主机 2、开启主机图形 3、配置网络可用 4、关闭VMware dhcp 功能 ​编辑​编辑 5、配置好本地仓库&#xff0c;方便后续下载 二、配置kickstart自动安装脚本的工具 1、 安装图形化生成kickstart自动安装脚本的工具 2、启动图…

2.MySQL库的操作

创建数据库 创建数据库的代码&#xff1a; CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [,create_specification] ...];​create_specification:[DEFAULT] CHARACTER SET charset_name[DEFAULT] COLLATE collation_name 说明&#xff1a; 大写的表示关键…

【隐私保护】无证书签名方案(CLS)

一、CLS方案提出的背景 无证书签名方案&#xff08;Certificateless Signature Scheme, CLS&#xff09;是一种旨在结合公钥基础设施&#xff08;PKI&#xff09;和基于身份的加密&#xff08;IBE&#xff09;的优点&#xff0c;同时避免它们缺点的加密技术。 CLS方案的主要目标…

【网络安全渗透测试零基础入门必知必会】之什么是文件包含漏洞分类(非常详细)零基础入门到精通,收藏这一篇就够了

一、前言 这是大白给粉丝盆友们整理的网络安全渗透测试入门阶段文件包含渗透与防御第1篇。 本文主要讲解什么是文件包含漏洞、本地文件包含漏洞 喜欢的朋友们&#xff0c;记得给大白点赞支持和收藏一下&#xff0c;关注我&#xff0c;学习黑客技术。 一、什么是文件包含漏洞…

【HarmonyOS NEXT星河版开发学习】小型测试案例07-弹性布局小练习

个人主页→VON 收录专栏→鸿蒙开发小型案例总结​​​​​ 基础语法部分会发布于github 和 gitee上面&#xff08;暂未发布&#xff09; 前言 在鸿蒙&#xff08;HarmonyOS&#xff09;开发中&#xff0c;Flex布局是一种非常有用的布局方式&#xff0c;它允许开发者创建灵活且响…

Spring Boot实战:拦截器

一.拦截器快速入门 1.1了解拦截器 什么是拦截器&#xff1a; 概念 &#xff1a;拦截器是Spring框架提供的核⼼功能之⼀, 主要⽤来拦截⽤⼾的请求, 在指定⽅法前后, 根据业务需要执⾏预先设定的代码。 也就是说, 允许开发⼈员提前预定义⼀些逻辑, 在⽤⼾的请求响应前后执⾏. 也…

ThinkPHP6与金仓数据库(Kingbase)集成:模型查询的解决方案

摘要&#xff1a; ThinkPHP6是一款流行的PHP框架&#xff0c;支持多种数据库。然而&#xff0c;对于金仓数据库&#xff08;Kingbase&#xff09;这种相对小众的数据库系统&#xff0c;开发者在使用ThinkPHP6进行模型查询时可能会遇到一些兼容性问题。本文将提供一种解决方案&a…