当前位置: 首页 > news >正文

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

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: Intval old = paint.typefaceoldStyle = old?.style ?: 0val 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 nullreturn 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 = 0val 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 + paddingLeftsetMeasuredDimension(maxWidth, measuredHeight)}
}private fun getMaxLineWidth(layout: Layout): Float {var maximumWidth = 0.0fval lines = layout.lineCountfor (i in 0 until lines) {maximumWidth = max(layout.getLineWidth(i), maximumWidth)}return maximumWidth
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Node.js-path 模块
  • 智能与伦理:Kimi与学术道德的和谐共舞
  • 流批一体计算引擎-13-[Flink]RuntimeExecutionMode和水印策略Watermark Strategy
  • 直播预告|飞思实验室暑期公益培训7月10日正式开启,报名从速!
  • Vue的学习之数据与方法
  • githup开了代理push不上去
  • leetcode力扣_排序问题
  • Symfony框架:优雅构建PHP应用的强有力工具
  • FFmpeg视频处理工具安装使用
  • Docker学习笔记(二)镜像、容器、仓库相关命令操作
  • uni-app x 跨平台开发框架
  • 【vue组件库搭建05】vitePress中使用vue/antd/demo预览组件
  • [Vite]Vite插件生命周期了解
  • Web漏洞扫描工具AppScan与AWVS测评及使用体验
  • 03:Spring MVC
  • 【译】JS基础算法脚本:字符串结尾
  • “大数据应用场景”之隔壁老王(连载四)
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • Git 使用集
  • Git初体验
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • Java精华积累:初学者都应该搞懂的问题
  • JWT究竟是什么呢?
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • node和express搭建代理服务器(源码)
  • React 快速上手 - 07 前端路由 react-router
  • Spring Cloud Feign的两种使用姿势
  • springMvc学习笔记(2)
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • 对JS继承的一点思考
  • 机器学习中为什么要做归一化normalization
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 学习使用ExpressJS 4.0中的新Router
  • 怎样选择前端框架
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • #07【面试问题整理】嵌入式软件工程师
  • #DBA杂记1
  • (14)Hive调优——合并小文件
  • (k8s)kubernetes集群基于Containerd部署
  • (MATLAB)第五章-矩阵运算
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (附源码)spring boot校园拼车微信小程序 毕业设计 091617
  • (强烈推荐)移动端音视频从零到上手(下)
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .NET Micro Framework 4.2 beta 源码探析
  • .NET Project Open Day(2011.11.13)
  • .NET是什么
  • ;号自动换行
  • @Autowired 与@Resource的区别
  • [ C++ ] 类和对象( 下 )
  • [ vulhub漏洞复现篇 ] Jetty WEB-INF 文件读取复现CVE-2021-34429