文字环绕图片效果实现

news2024/11/23 21:49:13

书接上回,我们来讲讲如何实现“文字环绕图片”的效果吧。整体预计实现的效果如下:

请添加图片描述

日常杂谈

我喜欢看动漫,接下来的所有博客都会和我日常生活结合在一起写,这样感觉会让自己的博客会有温度,我感觉每个人都应该有自己的爱好,动漫也是一种爱好,就和女孩喜欢看剧一样,没有什么高低贵贱之分,不是说喜欢打篮球就高人一等。不虚伪不做作,这才是我,最近在看“我推的孩子”。

正文

如果是单纯需要实现自动换行的效果,那么只需要通过StaticLayout的方式就能简单地绘制对应的文字换行效果。使用也是非常简单,我就不多赘述了。

val staticLayout =
    StaticLayout(
        textPlain, textPaint, width, Layout.Alignment.ALIGN_NORMAL,
        1f,
        textPaint.fontSpacing / 2, true
    )
staticLayout.draw(canvas)

但是如果希望实现我们上述所提及的文字环绕效果,通过上述的方式很明显是不够的,我们就需要具体情况具体分析,根据图片的位置来动态地确定文字应该绘制的位置。

首先我们来看一下大体的思路:

  1. 确定目的:我们需要在(width/2,height/4)的位置开始绘制一张图片,图片的宽度是width/2,然后图片的高度未知,因为我们需要保持图片的宽高比,总不能说,原来长方形的图片放进来之后就压缩成方形的了。

    fun getAvatar(context: Context, @DrawableRes drawableRes: Int, withInWidth: Int): Bitmap {
            val option = BitmapFactory.Options()
            option.inJustDecodeBounds = true
            BitmapFactory.decodeResource(resources, drawableRes, option)
            option.apply {
                inDensity = outWidth
                inTargetDensity = withInWidth
                inJustDecodeBounds = false
            }
            return BitmapFactory.decodeResource(resources, drawableRes, option)
        }
    
  2. 在对应的位置绘制对应的图片,并存储图片的左上角的纵坐标和左下角的纵坐标值

    val bitmap = getAvatar(context, R.drawable.avatar, width / 2)
            canvas.drawBitmap(bitmap, width/2f,height/4f, paint)
            val mipmapStartX = width / 4
            val mipmapStartY = height / 4
            val mipmapEndY = height / 4 +bitmap.height
    
  3. 逐行绘制文字,当文字绘制的纵坐标和图片的纵坐标有重合的时候,限制文字的绘制宽度

    var startIndex = 0
            val endIndex = textPlain.length
            var currentWidth = width
            var startY = -metrics.top
            var breakLen: Int = 0
            while (startIndex < endIndex) {
                val textTop = startY + metrics.top
                val textBottom = textTop + (metrics.bottom - metrics.top)
                currentWidth =
                    if (textBottom > mipmapStartY && textTop < mipmapEndY) {
                        width / 2
                    } else width
                breakLen = textPaint.breakText(
                    textPlain, startIndex, endIndex, true,
                    currentWidth.toFloat(), null
                )
    
                canvas.drawText(textPlain, startIndex, startIndex + breakLen, 0f, startY, textPaint)
                startIndex += breakLen
                startY += textPaint.fontSpacing
            }
    

    就这样,整体的环绕效果绘制就完成了。如下是完整的代码:

    /**
     * 绘制一个环绕图片的文字效果
     */
    class RoundAvatarTextView(context: Context, attrs: AttributeSet) : View(context, attrs) {
        private val paint: Paint = Paint().apply { isAntiAlias = true }
        private var metrics: Paint.FontMetrics = Paint.FontMetrics()
        private val textPaint: TextPaint = TextPaint().apply {
            textSize = 20.dp
        }
        val dstRectF = RectF(width/2f,height/4f,width.toFloat(),height/4f*3)
    
        private val textPlain = resources.getText(R.string.think)
        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            textPaint.getFontMetrics(metrics)
    
            val bitmap = getAvatar(context, R.drawable.avatar, width / 2)
            canvas.drawBitmap(bitmap, width/2f,height/4f, paint)
            val mipmapStartX = width / 4
            val mipmapStartY = height / 4
            val mipmapEndY = height / 4 +bitmap.height
    
            var startIndex = 0
            val endIndex = textPlain.length
            var currentWidth = width
            var startY = -metrics.top
            var breakLen: Int = 0
            while (startIndex < endIndex) {
                val textTop = startY + metrics.top
                val textBottom = textTop + (metrics.bottom - metrics.top)
                currentWidth =
                    if (textBottom > mipmapStartY && textTop < mipmapEndY) {
                        width / 2
                    } else width
                breakLen = textPaint.breakText(
                    textPlain, startIndex, endIndex, true,
                    currentWidth.toFloat(), null
                )
    
                canvas.drawText(textPlain, startIndex, startIndex + breakLen, 0f, startY, textPaint)
                startIndex += breakLen
                startY += textPaint.fontSpacing
            }
        }
    
        fun getAvatar(context: Context, @DrawableRes drawableRes: Int, withInWidth: Int): Bitmap {
            val option = BitmapFactory.Options()
            option.inJustDecodeBounds = true
            BitmapFactory.decodeResource(resources, drawableRes, option)
            option.apply {
                inDensity = outWidth
                inTargetDensity = withInWidth
                inJustDecodeBounds = false
            }
            return BitmapFactory.decodeResource(resources, drawableRes, option)
        }
    }
    

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

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

相关文章

最新喜讯|易知微入选2023数字孪生解决方案提供商TOP50

近日&#xff0c;互联网周刊发布《2023数字孪生解决方案提供商TOP50》&#xff0c;杭州易知微科技有限公司在榜。 中国科学院主管的《互联网周刊》&#xff0c;创刊于1998年&#xff0c;是中国最具公信力的杂志之一&#xff0c;其颁布的榜单极具权威性与专业度&#xff0c;对产…

基于非局部图注意力网络的鲁棒三维形状分类

文章目录 Robust 3D Shape Classification via Non-local Graph Attention Network摘要本文方法Global Structure Network (GSN)Global Relationship Network (GRN)Local Feature Learning based on MLP-STNetwork Channel Fusion ModuleGlobal descriptor 实验结果 Robust 3D …

分布式锁的应用场景与分布式锁实现(四):基于MySQL实现分布式锁与分布式锁总结

分布式锁的应用场景与分布式锁实现&#xff08;三&#xff09;&#xff1a;基于Zookeeper实现分布式锁 基于MySQL实现分布式锁 ​ 不管是JVM锁还是MySQL锁&#xff0c;为了保证线程的并发安全&#xff0c;都提供了悲观独占排他锁。所以独占排他也是分布式锁的基本要求。 ​ …

在can协议的基础下编写DBC文件,然后使用该DBC文件下发can协议到底盘完整流程

目录 前言一、VectorCANdb下载及安装二、DBC文件的编写1.新建dbc文件2.建立dbc2.1根据CAN协议设置以下的signals2.2设置报文2.3建立报文与信号的关系2.4建立节点 三、编写程序使用UDP通信下发can协议1.查看can口、电脑ip以及端口号2.编写测试程序 前言 最近完成了一个项目&…

热烈庆祝兴业法拍网与宁波银行北京分行签订“法拍贷”业务合作

6月1日&#xff0c;兴业法拍网与宁波银行北京分行签订“法拍贷”合作协议。 “法拍贷”是以法院房产拍卖为核心、线上平台拓宽拍卖渠道、保险公司提供阶段性保证、公证机构加大司法效力、银行提供全程金融服务的“14”创新合作模式。该模式汇聚五方合力让更多竞拍人享受到便利…

2天时间3个面试,百度进了3面!

昨天和朋友复盘了一下最近的面试经历&#xff0c;分享给大家&#xff1a; 关于就业环境 忠告&#xff1a;如果不是在二三线买车买房结婚生子了&#xff0c;还是到一线城市去吧。 或者换个行业&#xff01; 关于焦虑和摆烂 如果你也在焦虑迷茫、精神内耗。找阳哥给你做“心理…

spring-boot版本影响Spring AOP @Before @Around @After等执行顺序

郁闷了半天&#xff0c;我通过AOP切面打印的日志顺序怪怪的&#xff0c;网上查了好几篇文章都说没问题&#xff0c;最后发现是springboot版本升级后Before Around After等执行顺序发生了变化。 1.切面类 Aspect// 这是一个切面 Component// 这是一个需要被装配的spring bean S…

零基础如何实现 Python 自动化办公 ?

996 一直是互联网老生常谈的话题了&#xff0c;但抛开其他只谈工作本身&#xff0c;你有没有想过&#xff0c;下班晚、加班&#xff0c;有时候可能是因为自己工作比较低效&#xff1f; 在这给你分享一个案例&#xff1a; 场景是在维护日活超过 3 亿用户的微博私信平台&#x…

Linux开机rc.local不自启动执行脚本其他一些问题进行补充说明

Linux开机rc.local不自启动执行脚本其他一些问题进行补充说明 在上一篇&#xff0c;我们讲了Linux开机rc.local不自启动执行脚本问题的排查思路及问题解决 这一篇我们补充一些其他的问题 问题一&#xff1a;我怎么知道我rc.local里面的命令启动成功不成功呢&#xff0c;我怎…

为什么说 Java 比 C / C++ 慢?

因为C/C允许程序员做出更多选择。 选择更多&#xff0c;那么&#xff1a; 弊端&#xff1a;开发效率难以提高&#xff0c;因为有太多选择需要斟酌。 优势&#xff1a;执行效率可以逼近极限&#xff0c;因为不会有什么抽象拦住你。 举个例子吧&#xff1a;大家可能对Java无处不…

New bing出现“重定向”无法使用解决方法来了

我又来分享干货了&#xff01;&#xff01;&#xff01; 因为要润色论文&#xff0c;又是经过几天的折腾&#xff0c;终于可以正常使用bing聊天了&#xff0c;泪目&#xff01; 首先你要有VPN才能使用New bing聊天的&#xff01;要求使用edge浏览器&#xff08;虽然我最后用的…

电脑mp3转换器哪个好用?我来告诉你电脑mp3转换器哪个好

假如你下载了一些音乐或者录音文件&#xff0c;但是它们可能不是mp3格式的&#xff0c;而是其他格式&#xff0c;如wav、flac等。而有一些设备又只能播放mp3格式的音频&#xff0c;这时候就需要使用mp3转换器将其转换成mp3格式&#xff0c;以便于在各种设备上播放和分享。不过你…

RustChinaConf 2023官网上线,精彩议题早知道

随着大会日益临近&#xff0c;我们RustChinaConf 2023筹备委员会的工作也在有条不紊的进行中。最新的好消息来了&#xff0c;官网已上线&#xff0c;访问地址&#xff1a; https://rustcc.cn/2023rustchinaconf/ 从官网进去也可以报名&#xff01; 大会时间地址 6.17 - 6.1…

电影《异形》标志性雕塑将分割为500个NFT出售

由佳士得前高管领导的美术平台Particle曾创造历史般售出班克西的《爱在空中》的10000件数字作品。 5 月 31 日 - Particle &#xff0c;作为去中心化的艺术生态系统和Banksy 的“Love is in the Air”画作的代币商&#xff0c;它将让收藏者有机会购买H.R. Giger的《异形3》原创…

我发现3个国内一直能用的免费版ChatGPT 免登免注册无广告 再不赶紧保存就没啦!

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

Linux多Reactor多线程网络模型

多Reactor多线程网络模型是一种用于构建高性能网络应用的并发模型。它基于事件驱动的思想&#xff0c;通过使用多个Reactor线程和多个工作线程来处理并发的网络请求。 底层调用关系&#xff1a; 在多Reactor多线程网络模型中&#xff0c;通常会有一个主Reactor线程和多个工作线…

凌云出海 决胜万里丨华为云中企出海领袖班第五期顺利结束!

互联网大潮风起云涌&#xff0c;国内竞争日益激烈内卷&#xff0c;越来越多的互联网企业选择国际化走出去&#xff0c;在全球市场这个更大舞台上找寻机会。想要抓住技术红利并惠及企业全球化&#xff0c;成为当下众多出海从业者的共识。 为了帮助更多的CTO领袖具备更专业的国际…

【大模型】人工智能大模型在自动驾驶领域的应用

随着ChatGPT的火爆&#xff0c;大模型受到的关注度越来越高&#xff0c;大模型展现出的能力令人惊叹。 第一个问题&#xff1a;怎样的模型可以称之为大模型呢&#xff1f; 一般来说&#xff0c;我们认为参数量过亿的模型都可以称之为“大模型”。而在自动驾驶领域&#xff0c;大…

Hibernate框架【四】——基本映射——多对一和一对多映射

系列文章目录 Hibernate框架【三】——基本映射——一对一映射 基本映射——多对一和一对多映射 系列文章目录前言一、多对一映射是什么&#xff1f;1.案例&#xff1a;现在有两个实体User实体和Group&#xff0c;其中多个User属于一个Group&#xff0c;表现出多对一的关系。①…

图解LeetCode——98. 验证二叉搜索树

一、题目 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 二、示例 2.1>…