【HarmonyOS NEXT】实现文字环绕动态文本效果

打印 上一主题 下一主题

主题 942|帖子 942|积分 2836

一、配景

在开发鸿蒙应用时,我们常常需要实现一些复杂的布局效果,好比文字环绕动态文本的效果。这种效果类似于文字环绕图片,但需要环绕的文本是动态生成的,并且带有边框和样式。传统的布局组件(如 Row)无法直接实现这种效果,由于 Row 的换行逻辑是基于每个子组件的起始端,无法实现第二个文本环绕第一个文本的效果。
下面介绍如何通过 组件截图 和 ImageSpan 来实现文字环绕动态文本的效果。
二、实现思路

1. 初步实验:使用 Row 组件

最初的想法是使用 Row 组件包裹两个 Text 组件,分别表示需要环绕的文本和主文本。然而,Row 组件的布局方式是左右排列,当文本换行时,第二个 Text 组件会基于自己的起始端换行,无法实现环绕效果。
如下效果:

2. 解决方案:组件截图 + ImageSpan

为了实现文字环绕效果,采用了以下方案:

  • 使用 componentSnapshot 组件对需要环绕的文本进行截图,生成图片。
  • 将截图通过 ImageSpan 嵌入到主文本中,实现文字环绕图片的效果。
三、详细实现

3.1 组件截图:componentSnapshot

componentSnapshot 是鸿蒙 ArkUI 提供的一个 API,用于获取组件的截图。它支持截取已加载组件的内容,并将结果保存为 PixelMap 对象。
3.1.1 导入模块

起首,需要导入 componentSnapshot 模块:
  1. import { componentSnapshot } from '@kit.ArkUI';
复制代码
3.1.2 界说需要截图的组件

我们界说一个带有边框和样式的 Text 组件,作为需要环绕的文本:
  1. //获取需要加载组件的文本
  2.   @Builder
  3.   hotTopText() {
  4.     Text('精选')
  5.       .borderRadius(2)
  6.       .border({
  7.         width: 0.5,
  8.         color: '#0165B8',
  9.         style: BorderStyle.Solid
  10.       })
  11.       .fontSize(12)
  12.       .fontColor('#0165B8')
  13.       .backgroundColor('#DBEFFF')
  14.       .padding({
  15.         left: 2,
  16.         right: 2
  17.       })
  18.       .margin({ top: 5 })
  19.       .height(15)
  20.       .id('hotTopText') //组件标识
  21.       .visibility(this.isShowTag ? Visibility.Visible : Visibility.None)
  22.   }
复制代码
3.1.3 获取组件截图

通过 componentSnapshot.get 方法获取组件的截图:
  1. getComponentSnapshot() {
  2.     this.isShowTag = true
  3.     // 增加延迟,确保组件渲染完成
  4.     setTimeout(() => {
  5.       componentSnapshot.get('hotTopText', { scale: 2, waitUntilRenderFinished: true })
  6.         .then((pixmap: image.PixelMap) => {
  7.           this.pixmap = pixmap;
  8.           this.isShowTag = false
  9.         })
  10.         .catch(() => {
  11.           console.log('lucy== 获取标签快照失败')
  12.         });
  13.     }, 100);
  14.   }
复制代码
3.2 使用 ImageSpan 实现文字环绕

将截图通过 ImageSpan 嵌入到主文本中,实现文字环绕效果:
  1.     Row() {
  2.       this.hotTopText() //只有加载了才能获取截图
  3.       Text() {
  4.         ImageSpan(this.pixmap)
  5.           .height(14)
  6.           .width('auto')
  7.           .verticalAlign(ImageSpanAlignment.CENTER)
  8.           .margin({ right: 3 })
  9.           .objectFit(ImageFit.Contain)
  10.         Span('HarmonyOS NEXT 全栈自研架构,鸿蒙原生应用,带来全新体验')
  11.           .fontSize(15)
  12.           .fontWeight(FontWeight.Medium)
  13.       }
  14.       .align(Alignment.Top)
  15.       .textAlign(TextAlign.Start)
  16.     }
  17.     .margin({
  18.       top: 12,
  19.     })
  20.     .padding(12)
  21.     .borderWidth(1)
  22.     .borderColor(Color.Red)
复制代码
四、完整代码

以下是完整的实现代码:
  1. import { image } from '@kit.ImageKit'import { componentSnapshot } from '@kit.ArkUI'@Entry@Componentstruct TextSpanPage {  @State pixmap: image.PixelMap | undefined = undefined  @State isShowTag: boolean = false  aboutToAppear(): void {    this.getComponentSnapshot()  }  getComponentSnapshot() {
  2.     this.isShowTag = true
  3.     // 增加延迟,确保组件渲染完成
  4.     setTimeout(() => {
  5.       componentSnapshot.get('hotTopText', { scale: 2, waitUntilRenderFinished: true })
  6.         .then((pixmap: image.PixelMap) => {
  7.           this.pixmap = pixmap;
  8.           this.isShowTag = false
  9.         })
  10.         .catch(() => {
  11.           console.log('lucy== 获取标签快照失败')
  12.         });
  13.     }, 100);
  14.   }  build() {    Row() {
  15.       this.hotTopText() //只有加载了才能获取截图
  16.       Text() {
  17.         ImageSpan(this.pixmap)
  18.           .height(14)
  19.           .width('auto')
  20.           .verticalAlign(ImageSpanAlignment.CENTER)
  21.           .margin({ right: 3 })
  22.           .objectFit(ImageFit.Contain)
  23.         Span('HarmonyOS NEXT 全栈自研架构,鸿蒙原生应用,带来全新体验')
  24.           .fontSize(15)
  25.           .fontWeight(FontWeight.Medium)
  26.       }
  27.       .align(Alignment.Top)
  28.       .textAlign(TextAlign.Start)
  29.     }
  30.     .margin({
  31.       top: 12,
  32.     })
  33.     .padding(12)
  34.     .borderWidth(1)
  35.     .borderColor(Color.Red)  }  //获取需要加载组件的文本
  36.   @Builder
  37.   hotTopText() {
  38.     Text('精选')
  39.       .borderRadius(2)
  40.       .border({
  41.         width: 0.5,
  42.         color: '#0165B8',
  43.         style: BorderStyle.Solid
  44.       })
  45.       .fontSize(12)
  46.       .fontColor('#0165B8')
  47.       .backgroundColor('#DBEFFF')
  48.       .padding({
  49.         left: 2,
  50.         right: 2
  51.       })
  52.       .margin({ top: 5 })
  53.       .height(15)
  54.       .id('hotTopText') //组件标识
  55.       .visibility(this.isShowTag ? Visibility.Visible : Visibility.None)
  56.   }}
复制代码
五、最终效果
通过以上方法,实现了文字环绕动态文本的效果。动态文本被截图为图片,并通过 ImageSpan 嵌入到主文本中,实现了类似文字环绕图片的布局效果。




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

来自云龙湖轮廓分明的月亮

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表