HarmonyOS鸿蒙Next中属性字符串下的表达:打造高复用可定制化的协议弹窗
HarmonyOS鸿蒙Next中属性字符串下的表达:打造高复用可定制化的协议弹窗 尝试过使用Text组件进行拼接或者Text包裹TextSpan进行拼接,要么繁杂要么就是TextSpan的样式有限制,做不到完全定制化,有没有什么其它的方法实现这类需求场景?
属性字符串
- 方便灵活应用文本样式的对象,可通过TextController中的setStyledString方法与Text组件绑定,可通过RichEditorStyledStringController中的setStyledString方法与RichEditor组件绑定。
说明
从API version 12开始支持。
属性字符串目前不支持在worker线程中使用。
属性字符串通过controller绑定时,需要等待布局完成后,绑定生效。当measure和setStyledString同时使用,开发者需要通过@ohos.arkui.inspector (布局回调)判断布局完成,再绑定属性字符串。

先来看下真机效果:

前置条件:
在模块的module.json5文件中加上网络访问权限:以此满足协议的正常跳转
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
],
实现步骤:
1、自定义弹窗组件;
2、使用mutableStyledString给字符串自定义各种样式以及超链接;
3、使用Text()组件加载属性字符串。
注意:本案例仅作功能实现参考,具体封装细节请自己结合项目封装实现
完整代码:
@CustomDialog
export struct PrivacyDialog {
private control?: CustomDialogController
url1: UrlStyle =
new UrlStyle("https://term.developer.huaweicloud.com/rest/developer/agreementservice/v1/developer/agreement/agreement-template?agr_type=90109&language=zh_cn&version=2025111113®ion=cn");
url2: UrlStyle = new UrlStyle("https://developer.huawei.com/consumer/cn/devservice/use");
privacyStr = "欢迎使用 XXAPP!为了向您提供更优质的服务,我们需要获取以下权限:点击同意及表示您同意《生态隐私协议》和《开发者联盟网站使用条款》"
mutableStyledString: MutableStyledString =
new MutableStyledString(this.privacyStr);
textController: TextController = new TextController();
aboutToAppear(): void {
//匹配筛选出《》所包裹的超协议文本的字符串起始位置及长度
const urlRouterArr = matchBracketContent(this.privacyStr)
const urls = [this.url1, this.url2]
urlRouterArr.forEach((item, index) => {
//给特定文本加上超链接
this.mutableStyledString.setStyle({
start: item.start,
length: item.length,
styledKey: StyledStringKey.URL,
styledValue: urls[index],
})
//给超链接添加文本颜色
this.mutableStyledString.setStyle({
start: item.start,
length: item.length,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontColor: '#9980ff' })
})
})
this.textController.setStyledString(this.mutableStyledString);
}
build() {
Column() {
Text(undefined, { controller: this.textController }).key('mutableStyledString').fontSize(20)
.margin(20)
Divider().backgroundColor(Color.Gray)
Row() {
Text("不同意并退出")
.dialogBtn()
Text("同意")
.dialogBtn()
.borderRadius({ bottomRight: 15 })
}.borderRadius(15)
}
.borderRadius(15)
.width("100%")
}
}
@Extend(Text)
function dialogBtn() {
.layoutWeight(1)
.textAlign(TextAlign.Center)
.padding(20)
.fontSize(18)
}
export interface urlRouter {
start: number;
length: number;
}
/**
* 匹配字符串中所有《》包裹内容的起始位置和总长度
* @param str - 待匹配的原始字符串
* @returns 匹配结果数组,每个元素包含起始位置和长度信息
*/
function matchBracketContent(str: string): Array<urlRouter> {
const result: Array<urlRouter> = [];
const reg = /《[^》]+》/g;
let match: RegExpExecArray | null;
while ((match = reg.exec(str)) !== null) {
const fullContent = match[0];
const start = match.index;
const length = fullContent.length;
result.push({ start, length });
}
return result;
}
弹窗组件使用:
import { PrivacyDialog } from 'xx'
@Entry
@Component
struct Index {
dialogController: CustomDialogController = new CustomDialogController({
builder: PrivacyDialog()
})
build() {
Column() {
Button("唤起隐私弹窗").onClick(()=>{
this.dialogController.open()
})
}.justifyContent(FlexAlign.Center)
.height('100%')
.width('100%')
}
}
StyleOptions对象说明
| 名称 | 类型 | 只读 | 可选 | 说明 |
|---|---|---|---|---|
| start | number | 否 | 是 | 设置属性字符串样式的开始位置。当start的值小于0或超出字符串长度时,按0处理。 |
| length | number | 否 | 是 | 设置属性字符串样式的长度。当length的值小于0或超出字符串长度与start的差值时,按字符串长度与start的差值处理。 |
| styledKey | StyledStringKey | 否 | 否 | 样式类型的枚举值。 |
| styledValue | StyledStringValue | 否 | 否 | 样式对象。 |
StyledStringValue
| 类型 | 说明 |
|---|---|
| TextStyle | 文本字体样式。 |
| DecorationStyle | 文本装饰线样式。 |
| BaselineOffsetStyle | 文本基线偏移量样式。 |
| LetterSpacingStyle | 文本字符间距样式。 |
| LineHeightStyle | 文本行高样式。 |
| TextShadowStyle | 文本阴影样式。 |
| GestureStyle | 事件手势样式。 |
| ParagraphStyle | 文本段落样式。 |
| ImageAttachment | 图片样式。 |
| CustomSpan | 自定义绘制Span样式。 |
| UserDataSpan | UserDataSpan样式。 |
| UrlStyle | 超链接样式。 |
| BackgroundColorStyle | 文本背景颜色样式。 |
相关文档:
更多关于HarmonyOS鸿蒙Next中属性字符串下的表达:打造高复用可定制化的协议弹窗的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,属性字符串(AttributeString)支持通过富文本标记实现动态内容与样式定制。开发者可定义包含占位符和样式的字符串模板,运行时动态替换占位符内容,并应用预设样式(如颜色、字体)。这适用于协议弹窗等场景,通过分离文本内容与样式逻辑,提升UI组件的复用性和定制灵活性。
在HarmonyOS Next中,实现高复用、可定制化的协议弹窗文本,推荐使用Span组件进行富文本拼接,这是目前最灵活的方式。
核心方案:使用 Span 组件
Span 提供了 SpanStyle 来精细控制每个片段的样式(字体、颜色、装饰线等),并通过 onClick 事件为特定片段添加点击交互,完美契合协议弹窗中“用户协议”、“隐私政策”等可点击文本的需求。
示例代码:
// 构建富文本片段
let mySpans: Span[] = [
{
content: '请仔细阅读并同意',
style: SpanStyle.create({ fontSize: 16, fontColor: Color.Black })
},
{
content: '《用户协议》',
style: SpanStyle.create({ fontSize: 16, fontColor: Color.Blue, decoration: { type: TextDecorationType.Underline } }),
onClick: () => { /* 跳转用户协议 */ }
},
{
content: '和',
style: SpanStyle.create({ fontSize: 16, fontColor: Color.Black })
},
{
content: '《隐私政策》',
style: SpanStyle.create({ fontSize: 16, fontColor: Color.Blue, decoration: { type: TextDecorationType.Underline } }),
onClick: () => { /* 跳转隐私政策 */ }
}
]
// 在Text组件中使用
Text() {
Span() {
ForEach(mySpans, (item: Span) => {
Span(item.content)
.spanStyle(item.style)
.onClick(item.onClick) // 仅为可点击片段设置
})
}
}
关键优势:
- 样式完全解耦:每个文本片段的样式独立配置,支持字体、颜色、背景、装饰线、行高等。
- 交互精准绑定:可为任意片段单独设置点击事件,无需包装额外组件。
- 高性能复用:可将
Span数组封装成自定义组件或通用函数,通过参数动态生成不同文案和样式的协议文本。
对比其他方式:
- 纯
Text拼接:无法为局部文本添加独立交互。 Text+TextSpan:TextSpan的样式选项和交互能力确实有限。- 多个
Text组件行内排列:布局代码冗余,样式维护困难。
扩展建议:
对于更复杂的场景(如混合图标、自定义布局),可结合 Flex 或 Grid 布局,将 Span 与 Image 等组件内联排列。若弹窗内容整体需要复用,建议将其封装为 @Builder 构建函数或自定义组件,通过回调函数处理点击事件。
这种方式在保持代码简洁的同时,提供了最强的定制化能力,是目前 HarmonyOS Next 中处理此类需求的最佳实践。

