HarmonyOS鸿蒙Next中如何将kotlin自定义高亮文本组件转换成ArkTS
HarmonyOS鸿蒙Next中如何将kotlin自定义高亮文本组件转换成ArkTS
class HighlightTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatTextView(context, attrs, defStyleAttr) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
companion object {
const val HIGHLIGHT_RECT = 0 // 矩形高亮
const val HIGHLIGHT_ROUND = 1 // 圆形高亮
}
init {
paint.style = Paint.Style.FILL
}
private data class HighlightInfo(
val highlightText: String,
val highlightColor: Int,
val highlightStyle: Int,
var matchAll: Boolean,
)
private val highlights = mutableListOf<HighlightInfo>()
fun addHighlight(text: String, color: Int, style: Int, matchAll: Boolean) {
highlights.add(HighlightInfo(text, color, style, matchAll))
invalidate()
}
fun clearHighlights() {
highlights.clear()
invalidate()
}
override fun onDraw(canvas: Canvas) {
val content = text.toString()
// 获取文字的Paint参数
// val textPaint = getPaint()
// 获取文字的度量信息
// val fontMetrics = textPaint.fontMetrics
// 遍历所有高亮区域
for (highlight in highlights) {
var searchStart = 0
while (searchStart < content.length) {
// 直接查找完整匹配,包含换行符
val matchStart = content.indexOf(highlight.highlightText, searchStart)
if (matchStart == -1) break
val matchEnd = matchStart + highlight.highlightText.length
// 找到匹配,绘制高亮
val highlightViewLayout = layout
if (highlightViewLayout != null) {
// 获取起始位置所在的行
val startLine = highlightViewLayout.getLineForOffset(matchStart)
// 获取结束位置所在的行
val endLine = highlightViewLayout.getLineForOffset(matchEnd - 1)
// 遍历每一行进行绘制
for (line in startLine..endLine) {
// 计算当前行需要高亮的起始和结束位置
val lineStart = highlightViewLayout.getLineStart(line)
val lineEnd = highlightViewLayout.getLineEnd(line)
// 计算当前行实际需要高亮的范围
val highlightLineStart = maxOf(matchStart, lineStart)
// 调整行尾位置,如果是换行符则不包含它
val adjustedLineEnd = if (content.getOrNull(lineEnd - 1) == '\n') {
lineEnd - 1
} else {
lineEnd
}
val highlightLineEnd = minOf(matchEnd, adjustedLineEnd)
// 只有当当前行包含需要高亮的内容时才绘制
if (highlightLineStart <= highlightLineEnd) {
// 获取当前行文字的水平位置
val startX = highlightViewLayout.getPrimaryHorizontal(highlightLineStart)
// 使用当前行的实际结束位置
val endX = if (highlightLineEnd == lineEnd) {
// 如果是行尾,使用行宽
highlightViewLayout.getLineWidth(line).toFloat()
} else {
highlightViewLayout.getPrimaryHorizontal(highlightLineEnd)
}
val lineTop = highlightViewLayout.getLineTop(line)
val lineBottom = highlightViewLayout.getLineBottom(line)
paint.color = highlight.highlightColor
// 添加适当的padding
// 计算文字的实际高度
val lineHeight = lineBottom - lineTop
// MyLogger.d("lxp", "startX: $startX endX: $endX lineTop: $lineTop lineBottom: $lineBottom")
// MyLogger.d("lxp", "fontMetrics: ascent: ${fontMetrics.ascent} descent:${fontMetrics.descent} top: ${fontMetrics.top} bottom: ${fontMetrics.bottom}")
when (highlight.highlightStyle) {
HIGHLIGHT_RECT -> {
val verticalPadding = lineHeight * 0.45f // 可以调整这个值来控制padding
canvas.drawRect(
startX + paddingLeft,
lineTop.toFloat() + verticalPadding,
endX + paddingLeft,
lineBottom.toFloat(),
paint
)
}
HIGHLIGHT_ROUND -> {
val horizontalPadding = paddingLeft
// 遍历每个字符,分别绘制圆形背景
for (i in highlightLineStart until highlightLineEnd) {
val charStart = highlightViewLayout.getPrimaryHorizontal(i)
val charEnd = highlightViewLayout.getPrimaryHorizontal(i + 1)
val charWidth = charEnd - charStart
val centerX = (charStart + charEnd) / 2
val centerY = (lineTop + lineBottom) / 2f
val radius = (charWidth * 1.1f) / 2f
canvas.drawCircle(
centerX + horizontalPadding,
centerY,
radius,
paint
)
}
}
}
}
}
if (highlight.matchAll.not()) {
//只匹配第一个
break
}
searchStart = matchEnd
} else {
break
}
}
}
super.onDraw(canvas)
}
}
更多关于HarmonyOS鸿蒙Next中如何将kotlin自定义高亮文本组件转换成ArkTS的实战教程也可以访问 https://www.itying.com/category-93-b0.html
搞张效果图比放代码强
更多关于HarmonyOS鸿蒙Next中如何将kotlin自定义高亮文本组件转换成ArkTS的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,将Kotlin自定义高亮文本组件转换为ArkTS,需使用ArkUI声明式语法。Kotlin的View组件对应ArkTS的@Component自定义组件。文本高亮功能可通过Text组件的decoration属性设置,例如使用DecorationStyle的type属性指定下划线,color属性设置颜色。若需更复杂的高亮逻辑,可在自定义组件内使用@State装饰器管理状态,结合条件渲染或样式绑定实现动态高亮效果。直接重构为ArkTS组件即可,无需涉及Java或C语言。
在HarmonyOS Next中,将Kotlin自定义高亮文本组件转换为ArkTS,核心是利用ArkUI的声明式UI和自定义组件能力。原Kotlin View的onDraw绘制逻辑需要转换为ArkTS的@Builder绘制函数。
以下是关键转换步骤和ArkTS实现要点:
1. 组件结构定义
使用@Component定义自定义组件,通过@Prop或@State接收高亮配置。
@Component
export struct HighlightText {
@State message: string = '';
private highlights: HighlightInfo[] = [];
// 高亮信息结构
class HighlightInfo {
text: string;
color: ResourceColor;
style: HighlightStyle;
matchAll: boolean;
}
enum HighlightStyle {
RECT,
ROUND
}
}
2. 绘制逻辑转换
在aboutToAppear或@Builder中实现文本测量和高亮区域计算:
@Builder
private DrawHighlight(canvas: Canvas) {
this.highlights.forEach((highlight) => {
// 1. 使用TextMetrics测量文本
const textMetrics = new TextMetrics(this.message);
// 2. 查找匹配位置(支持matchAll逻辑)
let searchStart = 0;
while (searchStart < this.message.length) {
const matchStart = this.message.indexOf(highlight.text, searchStart);
if (matchStart === -1) break;
const matchEnd = matchStart + highlight.text.length;
// 3. 计算行位置和绘制区域
const lineInfo = textMetrics.getLineInfoForOffset(matchStart);
// ... 跨行处理逻辑
// 4. 根据style绘制
if (highlight.style === HighlightStyle.RECT) {
canvas.drawRect({
// 矩形坐标计算
});
} else {
// 圆形绘制逻辑
canvas.drawCircle({
// 圆形坐标计算
});
}
if (!highlight.matchAll) break;
searchStart = matchEnd;
}
});
}
3. 布局与绘制集成
在自定义组件的build()方法中嵌入Canvas进行绘制:
build() {
Column() {
// 底层:高亮绘制
Canvas(this.DrawHighlight)
.width('100%')
.height('100%')
// 上层:文本显示(使用透明背景)
Text(this.message)
.textAlign(TextAlign.Start)
.fontSize(16)
.backgroundColor(Color.Transparent)
}
}
4. API暴露 提供与Kotlin版本对应的方法:
// 添加高亮
addHighlight(text: string, color: ResourceColor,
style: HighlightStyle, matchAll: boolean): void {
this.highlights.push(new HighlightInfo(text, color, style, matchAll));
this.updateHighlight(); // 触发UI更新
}
// 清除高亮
clearHighlights(): void {
this.highlights = [];
this.updateHighlight();
}
private updateHighlight(): void {
// 通过状态变更触发重绘
}
关键差异处理:
- 文本测量:使用ArkUI的
TextMetrics替代Android的Layout.getLineForOffset - 坐标计算:Canvas坐标系基于组件左上角,需结合padding计算
- 性能优化:跨行高亮时注意绘制区域合并,避免过度绘制
- 响应式更新:通过
@State管理高亮数据,数据变更自动触发重绘
注意事项:
- ArkTS Canvas绘制是声明式的,每次数据变更都会重新执行
@Builder函数 - 复杂文本布局建议使用
TextLayout相关API进行精确测量 - 圆形高亮时需考虑字符间距和字体特性
这种转换保持了原有功能的核心逻辑,同时遵循了ArkUI的声明式编程范式。实际实现时需要根据具体文本样式(字体、大小、对齐方式)调整坐标计算。

