Read the original article:ArkUI ImageSpan Best Practices: Inline Comment Badges & OOM-Safe Sizing
ArkUI ImageSpan Best Practices: Inline Comment Badges & OOM-Safe Sizing
Requirement Description
Show a comment count (e.g., “11”) with a circular badge behind it, rendered inline with text.
Background Knowledge
Span: inline text inside
Text/ContainerSpan.ImageSpan: inline image inside
Text/ContainerSpan.
Docs:
Implementation Steps
- Use a hollow (transparent-center) PNG for the badge.
- Render number + badge inline:
Span(' 11 ')thenImageSpan(...). - Overlap with a negative left margin so the badge sits under the number.
- Pick a fixed vp size (phones ~24–28vp; watches ~16–22vp).
- Accessibility: the number stays text; the badge is decorative.
Code Snippet / Configuration
import { LengthUnit, LengthMetrics } from '@kit.ArkUI';
@Entry
@Component
struct WearableCommentBadgeSimple {
private badgeRes: Resource = $r('app.media.comment_badge_hollow')
build() {
Column({ space: 20 }) {
Text('Wearable Inline Badge Simple')
.fontSize('16fp')
.fontWeight(FontWeight.Medium)
.lineHeight('22vp')
.textAlign(TextAlign.Center)
.width('50%')
this.badgeRowSmall('Comments', '11')
this.badgeRowLarge('Activity', '100')
}
.padding(12)
.alignItems(HorizontalAlign.Center)
.backgroundColor("#ff736868")
.width('100%')
.height('100%')
}
@Builder
private badgeRowSmall(label: string, count: string) {
Row({ space: 8 }) {
Text(label)
.fontSize('13fp')
.fontColor('#B0B0B0')
.lineHeight('20vp')
Text() {
Span(` ${count} `)
.fontColor(Color.Black)
ImageSpan(this.badgeRes)
.width('30vp')
.height('30vp')
.baselineOffset(new LengthMetrics(-12, LengthUnit.VP))
.margin({ left: -28, top: 0 })
}
.fontSize('12fp')
.fontWeight(FontWeight.Medium)
.lineHeight('22vp')
}
.alignItems(VerticalAlign.Center)
}
@Builder
private badgeRowLarge(label: string, count: string) {
Row({ space: 8 }) {
Text(label)
.fontSize('13fp')
.fontColor('#B0B0B0')
.lineHeight('20vp')
Text() {
Span(` ${count} `)
.fontColor(Color.Black)
ImageSpan(this.badgeRes)
.width('44vp')
.height('44vp')
.margin({ left: -43.5, top: 0 })
.baselineOffset(new LengthMetrics(-18, LengthUnit.VP))
}
.fontSize('16fp')
.fontWeight(FontWeight.Medium)
.lineHeight('26vp')
}
.alignItems(VerticalAlign.Center)
}
}
Test Results
Limitations or Considerations
Large image crash (root cause & fix): If you write
Text() { ImageSpan(item.imgSrc) }
without size, ImageSpan uses the original bitmap dimensions, which can cause high memory usage and a crash for very large images.
Fix: always bound ImageSpan with explicit width/height (thumbnails ~80–160vp) or display big media with a normal Image outside of Text().
ImageSpan($r('app.media.BigImage'))
.width('120vp')
.height('120vp')
Wearables: round screens & tighter memory—prefer smaller badges (16–22vp) and verify line height/overflow.
Multi-digit counts: adjust badge size or margin for “100+”.

Top comments (0)