android iconfont带图标的图文并茂的一种实现

news2024/12/24 0:36:40

android实现图文并茂方法很多。
这里针对,仅本地图标,需要对齐,任意位置,兼容换行导致后面空白的问题做的一种方案。

www.iconfont.cn,注册;
上传svg的icon;
下载项目得到iconfont.ttf;
Typeface.createFromAsset得到TF。
替换unicode码iconfont的16进制,比如  改成\ue602
通过CustomTypefaceSpan, RelativeSizeSpan等修改语句中的unicode部分,拼接到ssb中设置给textView。

其他:
iconfont 某些svg上传到iconfont出现图标不对的问题。
参考:
https://zhuanlan.zhihu.com/p/494625217
第1个,先做outline stroke,轮廓化描边;
第2个,将多个图层合并成一层;
第3个,使用插件fill rule editor调整。

效果图:
在这里插入图片描述

class CustomTypefaceSpan(family: String?, private val newType: Typeface) : TypefaceSpan(family) {

    override fun updateDrawState(ds: TextPaint) {
        applyCustomTypeFace(ds, newType)
    }

    override fun updateMeasureState(paint: TextPaint) {
        applyCustomTypeFace(paint, newType)
    }

    companion object {
        private fun applyCustomTypeFace(paint: Paint, tf: Typeface) {
            val oldStyle: Int
            val old = paint.typeface
            oldStyle = old?.style ?: 0
            val fake = oldStyle and tf.style.inv()
            if (fake and Typeface.BOLD != 0) {
                paint.isFakeBoldText = true
            }
            if (fake and Typeface.ITALIC != 0) {
                paint.textSkewX = -0.25f
            }
            paint.typeface = tf
        }
    }
}

//如果有必要cache就通过hashmap来cache
fun getOrCreateFontFace(context: Context, assetsPath: String?) : Typeface? {
    if(assetsPath.isNullOrEmpty()) return null
    return Typeface.createFromAsset(context.assets, assetsPath)
}

/**
 * 一部分一部分的拼接
 */
interface IIconFontPart

/**
 * 拼接文字
 */
data class IconFontNormalPart(val normalText:String) : IIconFontPart

/**
 * 拼接上一个unicode的iconFont
 */
open class IconFontIconPart(val unicode:Char, val colorStr:String? = null, val relativeSize:Float? = null) : IIconFontPart

/**
 * 要求TextView自身已经具有常规的字体;常规的textSize;常规的颜色。
 *
 * 再来设置结合iconFontPart。
 */
fun TextView.setIconFont(vararg parts:IIconFontPart) {
    val sb = StringBuilder()
    parts.forEach {
        if (it is IconFontNormalPart) {
            sb.append(it.normalText)
        } else if (it is IconFontIconPart) {
            sb.append(it.unicode)
        }
    }
    val text = sb.toString()
    val ss = SpannableStringBuilder(text)

    var len = 0
    val iconTf = getOrCreateFontFace(globalContext, "fonts/iconfont.ttf")!!
    parts.forEach {
        if (it is IconFontNormalPart) {
            len += it.normalText.length
        } else if (it is IconFontIconPart) {
            ss.setSpan(CustomTypefaceSpan("", iconTf), len, len + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
            if (it.colorStr != null) {
                ss.setSpan(ForegroundColorSpan(Color.parseColor(it.colorStr)), len, len + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
            }
            if (it.relativeSize != null) {
                ss.setSpan(RelativeSizeSpan(it.relativeSize), len, len + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
            }
            len += 1 //最后
        }
    }
    setText(ss)
}

那么使用上就会很简单了。

val blank = IconFontNormalPart(" ")
 binding.textView.setIconFont(
     IconFontNormalPart("小明和小红 "),
     IconFontIconPart('\ue602'),
     blank,
     IconFontIconPart('\ue604'),
     blank,
     IconFontIconPart('\ue604', relativeSize = 1.25f),
     IconFontNormalPart("一起去打水 "),
     IconFontIconPart('\ue604', colorStr = "#ff8899"),)

自动换行右侧空白问题

英文的自动换行可能会导致文字显示过长,而自动换行后右侧空出太多,如下图:
请添加图片描述
解决方案给基础TextView继承后添加代码:

//解决换行右侧太多的问题
var fixWrapEndSpace = false

//https://stackoverflow.com/questions/50287198/textview-remove-space-after-line-break
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    if (fixWrapEndSpace) {
        var maxWidth = ceil(getMaxLineWidth(layout)).toInt()
        maxWidth += paddingRight + paddingLeft
        setMeasuredDimension(maxWidth, measuredHeight)
    }
}

private fun getMaxLineWidth(layout: Layout): Float {
    var maximumWidth = 0.0f
    val lines = layout.lineCount
    for (i in 0 until lines) {
        maximumWidth = max(layout.getLineWidth(i), maximumWidth)
    }

    return maximumWidth
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

泰雷茲具有首个通过FIPS 140-3 三级认证的HSMs

泰雷兹LunaHsm是业界首款通过FIPS140-33级认证的解决方案,安策引进泰雷兹HSM产品可以帮助您满足您的数据安全合规性需求,阻力企业提高竞争力。 安策提供泰雷茲ThalesLunaHSMs成为首个通过FIPS140-3三级认证的硬件安全模块图 我们很高兴地宣布&#xff0c…

Java 汉诺塔问题 详细分析

汉诺塔 汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小…

Ignis 应用: 社交 + 游戏 + 工业4.0,Ignis 构建Web3生态圈

引言 在数字经济快速发展的今天,Web3技术为我们带来了前所未有的变革。作为Ardor平台的主要子链,Ignis公链在推动Web3生态系统建设中扮演了重要角色。本文将通过介绍Vessel Chain、Mythical Beings和Bridge Champ等应用,探讨Ignis公链如何通…

Android原生与flutter模块交互

Flutter定义了三种不同类型的Channel: BasicMessageChannel:用于传递字符串和半结构化的信息,持续通信,收到消息后可以回复此次消息,如:Native将遍历到的文件信息陆续传递到Dart,在比如&#xf…

【Python机器学习系列】建立决策树模型预测小麦品种(案例+源码)

这是我的第314篇原创文章。 一、引言 对于表格数据,一套完整的机器学习建模流程如下: 针对不同的数据集,有些步骤不适用,其中橘红色框为必要步骤,欢迎大家关注翻看我之前的一些相关文章。前面我介绍了机器学习模型的二…

MySQL 9.0 发布了!

从昨晚开始,在DBA群里大家就在讨论MySQL 9.0发布的事情,但是Release Note和官方文档都没有更新,所以今天早上一上班就赶紧瞅了下具体更新了哪些内容? 整体看来,基本没什么创新。下面是9.0新增或废弃的一些特性。 &…

自动批量将阿里云盘文件发布成WordPress文章脚本源码(以RiPro主题为例含付费信息下载地址SEO等自动设置)源码

背景 很多资源下载站,付费资源下载站,付费内容查看等都可以用WordPress站点发布内容,这些站点一般会基于一个主题,付费信息作为文章附属的信息发布,底层存储在WP表里,比如日主题,子比主题等。 …

计算机是如何看到图像的

本节课为「计算机视觉 CV 核心知识」第 4 节; 「AI秘籍」系列课程: 人工智能应用数学基础人工智能Python基础人工智能基础核心知识人工智能BI核心知识人工智能CV核心知识 本文涉及代码:https://github.com/hivandu/AI_Cheats Hi, 大家好。我…

【MySQL备份】Percona XtraBackup压缩备份实战篇

目录 1.前言 2.准备工作 2.1.环境信息 2.2.配置/etc/my.cnf文件 2.3.授予root用户BACKUP_ADMIN权限 2.4.安装qpress 3. 压缩备份 3.1.创建压缩备份 3.2.创建全量备份 3.3.对比两个备份的大小 4.解压备份 5.准备备份 6.备份恢复 ​7.问题分析 8.总结 "实战…

网络连接之队头阻塞!!!

一、什么是队头阻塞 队头阻塞,在网络模型中简单理解就是,对于队列型的请求模型,如HTTP的请求-响应模型、TCP的ACK确认机制,都依赖得到一个具体的响应包,如果收不到这个响应包,那下一个请求就不能发&#x…

太阳辐射系统日光全光谱模拟太阳光模拟器

太阳光模拟器是一种用于评估太阳能电池性能的重要设备。它能够模拟太阳光的特性,通过测试电池的短路电流、开路电压、填充因子和光电转化效率等关键指标,来评估电池的性能优劣。 设备型号:KYF-GC004品牌制造商:科迎法电气太阳光模…

08 docker Registry搭建docker私仓

目录 本地镜像发布流程 1. docker pull registry 下载镜像 2. docker run 运行私有库registry 3. docker commit 构建镜像 4. docker tag 修改新镜像,使之符合私服规范tag 5. 修改配置文件使之支持http 6. curl验证私服库上有什么镜像 7. push推送 pull拉取 …

C# WPF自制批注工具(方便标记重点和演示)

在教学和演示中,我们通常需要对重点进行批注,下载安装第三方工具批注显得很麻烦。本篇使用WPF开发了一个批注工具,工具小巧,功能丰富,非常使用日常免费使用,或者进行再次开发。 自制批注工具具有以下功能特…

构建 Audio Unit 的流程

构建 Audio Unit 的流程 构建 Audio Unit 的流程指定 Audio Unit 的类型创建 Audio Unit设置 Audio Unit 的属性 构建 Audio Unit 的流程 iOS 有一个用于直接处理 audio units 的 API,另一个用于处理 audio processing graphs,可以同时使用这两种 API。…

第十四章 路由器 OSPF 动态路由配置

实验目的 掌握 OSPF 协议的配置方法: 掌握查看通过动态路由协议 OSPF 学习产生的路由; 熟悉广域网线缆的链接方式; 实验背景 假设校园网通过一台三层交换机连到校园网出口路由器上, 路由器再和校园外的另一台路由器连接。…

【C++题解】1456. 淘淘捡西瓜

问题:1456. 淘淘捡西瓜 类型:贪心 题目描述: 地上有一排西瓜,每个西瓜都有自己的重量。淘淘有一个包,包的容量是固定的,淘淘希望尽可能在包里装更多的西瓜(当然要装整个的,不能切开…

开放签电子签章,让签字有迹可循

开放签(企业版)V2.0.5版本上线后,系统支持一键查询电子文件的签署操作记录,支持一键生成详细的签署记录报告,详细请看下图: 1、操作记录详情: 从合同发起、填写、签署、撤销等环节全流程展示操…

创新与增长:eBest完美收官FBIF2024食品创新展

FBIF2024食品创新展今天在上海会展中心圆满落幕。此次大会以食品创新、渠道创新、营销创新及科技创新为主题,为众多参展企业及来宾带来一场蕴含创新思维的盛宴。 为什么要“破卷出新”?如今中国食品品牌面临的最大挑战就是在国内饱和的市场里出爆品&…

CTFHUB-SSRF-Redis协议

本题需要用到: 在线编码网址:https://icyberchef.com/ gopherus工具:https://mp.csdn.net/mp_blog/creation/editor/139440201 开启题目,页面空白 和上一个题FastCGI协议一样,还是使用gopherus攻击redis ./gopheru…

【操作与配置】VSCode配置Python

Python环境配置 可以参见:【操作与配置】Python:CondaPycharm_pycharmconda-CSDN博客 官网下载Python:http://www.python.org/download/官网下载Conda:Miniconda — Anaconda documentation VSCode插件安装 插件安装后需重启V…