一、背景
在开发鸿蒙应用时,我们常常需要实现一些复杂的布局效果,比如文字环绕动态文本的效果。这种效果类似于文字环绕图片,但需要环绕的文本是动态生成的,并且带有边框和样式。传统的布局组件(如 Row
)无法直接实现这种效果,因为 Row
的换行逻辑是基于每个子组件的起始端,无法实现第二个文本环绕第一个文本的效果。
下面介绍如何通过 组件截图 和 ImageSpan 来实现文字环绕动态文本的效果。
二、实现思路
1. 初步尝试:使用 Row
组件
最初的想法是使用 Row
组件包裹两个 Text
组件,分别表示需要环绕的文本和主文本。然而,Row
组件的布局方式是左右排列,当文本换行时,第二个 Text
组件会基于自己的起始端换行,无法实现环绕效果。
如下效果:

2. 解决方案:组件截图 + ImageSpan
为了实现文字环绕效果,采用了以下方案:
-
使用
componentSnapshot
组件对需要环绕的文本进行截图,生成图片。 -
将截图通过
ImageSpan
嵌入到主文本中,实现文字环绕图片的效果。
三、具体实现
3.1 组件截图:componentSnapshot
componentSnapshot
是鸿蒙 ArkUI 提供的一个 API,用于获取组件的截图。它支持截取已加载组件的内容,并将结果保存为 PixelMap
对象。
3.1.1 导入模块
首先,需要导入 componentSnapshot
模块:
import { componentSnapshot } from '@kit.ArkUI';
3.1.2 定义需要截图的组件
我们定义一个带有边框和样式的 Text
组件,作为需要环绕的文本:
javascript
//获取需要加载组件的文本
@Builder
hotTopText() {
Text('精选')
.borderRadius(2)
.border({
width: 0.5,
color: '#0165B8',
style: BorderStyle.Solid
})
.fontSize(12)
.fontColor('#0165B8')
.backgroundColor('#DBEFFF')
.padding({
left: 2,
right: 2
})
.margin({ top: 5 })
.height(15)
.id('hotTopText') //组件标识
.visibility(this.isShowTag ? Visibility.Visible : Visibility.None)
}
3.1.3 获取组件截图
通过 componentSnapshot.get
方法获取组件的截图:
javascript
getComponentSnapshot() {
this.isShowTag = true
// 增加延迟,确保组件渲染完成
setTimeout(() => {
componentSnapshot.get('hotTopText', { scale: 2, waitUntilRenderFinished: true })
.then((pixmap: image.PixelMap) => {
this.pixmap = pixmap;
this.isShowTag = false
})
.catch(() => {
console.log('lucy== 获取标签快照失败')
});
}, 100);
}
3.2 使用 ImageSpan
实现文字环绕
将截图通过 ImageSpan
嵌入到主文本中,实现文字环绕效果:
javascript
Row() {
this.hotTopText() //只有加载了才能获取截图
Text() {
ImageSpan(this.pixmap)
.height(14)
.width('auto')
.verticalAlign(ImageSpanAlignment.CENTER)
.margin({ right: 3 })
.objectFit(ImageFit.Contain)
Span('HarmonyOS NEXT 全栈自研架构,鸿蒙原生应用,带来全新体验')
.fontSize(15)
.fontWeight(FontWeight.Medium)
}
.align(Alignment.Top)
.textAlign(TextAlign.Start)
}
.margin({
top: 12,
})
.padding(12)
.borderWidth(1)
.borderColor(Color.Red)
四、完整代码
以下是完整的实现代码:
javascript
import { image } from '@kit.ImageKit'
import { componentSnapshot } from '@kit.ArkUI'
@Entry
@Component
struct TextSpanPage {
@State pixmap: image.PixelMap | undefined = undefined
@State isShowTag: boolean = false
aboutToAppear(): void {
this.getComponentSnapshot()
}
getComponentSnapshot() {
this.isShowTag = true
// 增加延迟,确保组件渲染完成
setTimeout(() => {
componentSnapshot.get('hotTopText', { scale: 2, waitUntilRenderFinished: true })
.then((pixmap: image.PixelMap) => {
this.pixmap = pixmap;
this.isShowTag = false
})
.catch(() => {
console.log('lucy== 获取标签快照失败')
});
}, 100);
}
build() {
Row() {
this.hotTopText() //只有加载了才能获取截图
Text() {
ImageSpan(this.pixmap)
.height(14)
.width('auto')
.verticalAlign(ImageSpanAlignment.CENTER)
.margin({ right: 3 })
.objectFit(ImageFit.Contain)
Span('HarmonyOS NEXT 全栈自研架构,鸿蒙原生应用,带来全新体验')
.fontSize(15)
.fontWeight(FontWeight.Medium)
}
.align(Alignment.Top)
.textAlign(TextAlign.Start)
}
.margin({
top: 12,
})
.padding(12)
.borderWidth(1)
.borderColor(Color.Red)
}
//获取需要加载组件的文本
@Builder
hotTopText() {
Text('精选')
.borderRadius(2)
.border({
width: 0.5,
color: '#0165B8',
style: BorderStyle.Solid
})
.fontSize(12)
.fontColor('#0165B8')
.backgroundColor('#DBEFFF')
.padding({
left: 2,
right: 2
})
.margin({ top: 5 })
.height(15)
.id('hotTopText') //组件标识
.visibility(this.isShowTag ? Visibility.Visible : Visibility.None)
}
}
五、最终效果
通过以上方法,实现了文字环绕动态文本的效果。动态文本被截图为图片,并通过 ImageSpan
嵌入到主文本中,实现了类似文字环绕图片的布局效果。

