Read the original article:Inline Text Highlighting Style Implementation
Requirement Description
In scenarios such as text editing, search boxes, keyword prompts, or lyrics display, certain words need to be highlighted. How can this functionality be implemented in HarmonyOS ArkUI?
Background Knowledge
When developing text display and editing features, several key components and APIs can be used to enhance the user experience:
- Span Component: A subcomponent of Text, used for inline text with customizable attributes.
- AttributeModifier: Provides methods to modify attributes dynamically.
- RichEditor: Supports mixed text and graphics editing with real-time style updates.
- MutableStyledString: Allows flexible text styling bound to Text via TextController.setStyledString.
Implementation Steps
You should use on of these steps:
- Use span in Text Component
- Attribute Modifier with Span
- RichEditor with addTextSpan
- MutableStyledString with TextController
Code Snippet / Configuration
Solution 1: Using Span in Text Component
@Entry
@Component
struct Page {
@State searchValue: string = 'drunk';
@State dataArr: string[] = [
'Resting by the window, drunk eyes gazing at the mountains',
'Under the begonia flowers, lost in the spring breeze',
'Drunk, I light the lamp and look at the sword, dreaming of the battlefield',
'After being drunk, not knowing the sky is in the water, a boat full of dreams pressed by the stars',
'Pointing to Dongting as wine, drinking deeply when thirsty, Mount Jun as a pillow, sleeping soundly after drunk'
]
build() {
Row() {
Column() {
ForEach(this.dataArr, (item: string) => {
Row() {
Text() {
Span(item.substring(0, item.indexOf(this.searchValue)))
// Highlighted word in red
Span(this.searchValue).fontColor(Color.Red)
Span(item.substring(item.indexOf(this.searchValue) + this.searchValue.length, item.length - 1))
// Last character in blue
Span(item.substring(item.length - 1)).fontColor(Color.Blue)
}
}
.width('100%')
.height(40)
.justifyContent(FlexAlign.Center)
})
}
}
}
}
Solution 2: AttributeModifier with Span
@Entry
@Component
struct Index {
@State searchValue: string = 'drunk';
@State dataArr: string[] = [
'Resting by the window, drunk eyes gazing at the mountains',
'Under the begonia flowers, lost in the spring breeze',
'Drunk, I light the lamp and look at the sword, dreaming of the battlefield',
'After being drunk, not knowing the sky is in the water, a boat full of dreams pressed by the stars',
'Pointing to Dongting as wine, drinking deeply when thirsty, Mount Jun as a pillow, sleeping soundly after drunk'
]
build() {
Column() {
ForEach(this.dataArr, (item: string) => {
Row() {
Text() {
// Multiple keyword matching
Span(item.substring(0, item.indexOf(this.searchValue))).attributeModifier(new HighlightModifier(false))
Span(this.searchValue).attributeModifier(new HighlightModifier(true))
Span(item.substring(item.indexOf(this.searchValue) + this.searchValue.length, item.length - 1))
.attributeModifier(new HighlightModifier(false))
}
}
.height(40)
.justifyContent(FlexAlign.Center)
})
}.justifyContent(FlexAlign.Center)
}
}
export class HighlightModifier implements AttributeModifier<SpanAttribute> {
isHighlight: boolean = false
constructor(isHighlight: boolean) {
this.isHighlight = isHighlight
}
applyNormalAttribute(instance: SpanAttribute): void {
instance.fontColor(this.isHighlight ? Color.Red : Color.Black).fontSize(15)
}
}
Solution 3: RichEditor with addTextSpan
@Entry
@Component
struct Page {
@State value: string = 'drunk';
@State dataArr: Tmp[] = [
new Tmp(new RichEditorController(), 'Resting by the window, drunk eyes gazing at the mountains'),
new Tmp(new RichEditorController(), 'Under the begonia flowers, lost in the spring breeze'),
new Tmp(new RichEditorController(), 'Drunk, I light the lamp and look at the sword, dreaming of the battlefield'),
new Tmp(new RichEditorController(), 'After being drunk, not knowing the sky is in the water, a boat full of dreams pressed by the stars'),
new Tmp(new RichEditorController(), 'Pointing to Dongting as wine, drinking deeply when thirsty, Mount Jun as a pillow, sleeping soundly after drunk'),
]
build() {
Column() {
ForEach(this.dataArr, (item: Tmp) => {
ListItem() {
Row() {
RichEditor({ controller: item.controller })
.onReady(() => {
// Add text span with normal style
item.controller.addTextSpan(item.value.substring(0, item.value.indexOf(this.value)),
{
style: { fontColor: Color.Black, fontSize: 16 }
})
// Add highlighted text span
item.controller.addTextSpan(this.value,
{
style: { fontColor: Color.Red, fontSize: 16 }
})
// Add remaining text span
item.controller.addTextSpan(item.value.substring(item.value.indexOf(this.value) + this.value.length),
{
style: { fontColor: Color.Black, fontSize: 16 }
})
})
}.width('100%').height(40).justifyContent(FlexAlign.Center)
}
})
}
}
}
class Tmp {
controller: RichEditorController
value: string
constructor(controller: RichEditorController, value: string) {
this.controller = controller
this.value = value
}
}
Solution 4: MutableStyledString with TextController
@Entry
@Component
struct Page {
@State value: string = '';
@State dataArr: string[] = [
'Resting by the window, drunk eyes gazing at the mountains',
'Under the begonia flowers, lost in the spring breeze',
'Drunk, I light the lamp and look at the sword, dreaming of the battlefield',
'After being drunk, not knowing the sky is in the water, a boat full of dreams pressed by the stars',
'Pointing to Dongting as wine, drinking deeply when thirsty, Mount Jun as a pillow, sleeping soundly after drunk'
]
@State showArr: Tmp[] = []
Style1: TextStyle = new TextStyle({ fontColor: Color.Red });
Style2: TextStyle = new TextStyle({ fontColor: Color.Blue });
build() {
Row() {
Column() {
Search({ value: $$this.value, placeholder: 'Type to search...' })
.onChange(() => {
this.showArr = []
this.dataArr.filter((item: string) => {
let index = item.indexOf(this.value)
// Match keyword and apply corresponding style
if (this.value && index != -1) {
let mutableStyledString = new MutableStyledString(item, [
{
start: index,
length: this.value.length,
styledKey: StyledStringKey.FONT,
styledValue: this.Style1
},
{
start: item.length - 1,
length: 1,
styledKey: StyledStringKey.FONT,
styledValue: this.Style2
}])
this.showArr.push(new Tmp(mutableStyledString, new TextController()))
}
})
})
ForEach(this.showArr, (item: Tmp) => {
Row() {
Text(undefined, { controller: item.controller })
.onAppear(() => {
// Apply styled string with setStyledString
item.controller.setStyledString(item.style)
})
}.width('100%').height(40).justifyContent(FlexAlign.Center)
})
}
}
}
}
class Tmp {
style: MutableStyledString
controller: TextController
constructor(style: MutableStyledString, controller: TextController) {
this.style = style
this.controller = controller
}
}
Test Results
- Solution 1 & 2: Simple inline highlighting in
Text. - Solution 3 & 4: Richer, suited for complex text editing scenarios.
Limitations or Considerations
- API Version 20 Release
- HarmonyOS 6.0.0 Release SDK
- DevEco Studio 6.0.0 Release
Top comments (0)