1# Styled String (StyledString/MutableStyledString)
2
3Styled strings, implemented by **StyledString** or **MutableStyledString** (collectively referred to as **StyledString**, with **MutableStyledString** inheriting from **StyledString**), are powerful markup objects designed to set text styles at the character or paragraph level. By binding a **StyledString** object to a text component, you can modify the text in various ways, including changing the font size, adding font colors, making the text clickable, and customizing the drawing of text, among others. For details, see [Styled String](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md).
4
5Styled strings provide a variety of style objects that cover various common text formatting styles, such as text decorative lines, line height, and text shadows. You can also create **CustomSpan** objects to apply custom styles.
6
7## Creating and Applying a StyledString Object
8
9  You can bind a **StyledString** object to a text component using the [setStyledString](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#setstyledstring12) API provided by **TextController**. You are advised to call the API in the [onPageShow](../reference/apis-arkui/arkui-ts/ts-custom-component-lifecycle.md#onpageshow) callback for immediate display of the styled string text content.
10  > **NOTE**
11  >
12  > Avoid calling the **setStyledString** API in **aboutToAppear**, as the component may have not yet been mounted to the node tree at the time **aboutToAppear** is executed, preventing the styled string text content from appearing upon page load.
13
14  ```ts
15  @Entry
16  @Component
17  struct styled_string_demo1 {
18    styledString1: StyledString = new StyledString("45-minute workout");
19    mutableStyledString1: MutableStyledString = new MutableStyledString("35-minute workout");
20    controller1: TextController = new TextController();
21    controller2: TextController = new TextController();
22
23    async onPageShow() {
24      this.controller1.setStyledString(this.styledString1)
25      this.controller2.setStyledString(this.mutableStyledString1)
26    }
27
28    build() {
29      Column() {
30        // Display the styled string.
31        Text(undefined, { controller: this.controller1 })
32        Text(undefined, { controller: this.controller2 })
33      }
34      .width('100%')
35    }
36  }
37  ```
38  ![StyledString_Init](figures/span_string_init.png)
39
40## Setting the Text Style
41
42Styled strings offer multiple style objects, such as [TextStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#textstyle), [TextShadowStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#textshadowstyle), [DecorationStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#decorationstyle), [BaselineOffsetStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#baselineoffsetstyle), [LineHeightStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#lineheightstyle), and [LetterSpacingStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#letterspacingstyle), for setting text styles.
43
44- Creating and applying a **TextStyle** object
45
46  ```ts
47  import { LengthMetrics } from '@kit.ArkUI'
48  @Entry
49  @Component
50  struct styled_string_demo2 {
51    textStyleAttrs: TextStyle = new TextStyle({ fontWeight: FontWeight.Bolder, fontSize: LengthMetrics.vp(24), fontStyle: FontStyle.Italic })
52    mutableStyledString: MutableStyledString = new MutableStyledString("35-minute workout goal achieved", [
53      {
54        start: 2,
55        length: 2,
56        styledKey: StyledStringKey.FONT,
57        styledValue: this.textStyleAttrs
58      },
59      {
60        start: 7,
61        length: 4,
62        styledKey: StyledStringKey.FONT,
63        styledValue: new TextStyle({ fontColor: Color.Orange, fontSize: LengthMetrics.vp(12)})
64      }
65    ]);
66    controller: TextController = new TextController();
67
68    async onPageShow() {
69      this.controller.setStyledString(this.mutableStyledString)
70    }
71
72    build() {
73      Column() {
74        // Display the styled string.
75        Text(undefined, { controller: this.controller })
76          .margin({ top: 10 })
77      }
78      .width('100%')
79    }
80  }
81  ```
82  ![StyledString_TextStyle](figures/StyledString_TextStyle.png)
83
84- Creating and applying a **TextShadowStyle** object
85
86  ```ts
87  // xxx.ets
88  @Entry
89  @Component
90  struct styled_string_demo3 {
91    mutableStyledString: MutableStyledString = new MutableStyledString("35-minute workout", [
92    {
93      start: 0,
94      length: 3,
95      styledKey: StyledStringKey.TEXT_SHADOW,
96      styledValue: new TextShadowStyle({
97        radius: 5,
98        type: ShadowType.COLOR,
99        color: Color.Red,
100        offsetX: 10,
101        offsetY: 10
102      })
103    }
104    ]);
105    controller: TextController = new TextController();
106
107    async onPageShow() {
108      this.controller.setStyledString(this.mutableStyledString)
109    }
110
111    build() {
112      Column() {
113        // Display the styled string.
114        Text(undefined, { controller: this.controller })
115      }
116      .width('100%')
117    }
118  }
119  ```
120  ![StyledString_TextShadow](figures/styled_string_text_shadow.png)
121
122- Creating and applying a **Text DecorationStyle** object
123
124  ```ts
125  // xxx.ets
126  @Entry
127  @Component
128  struct styled_string_demo4 {
129    mutableStyledString: MutableStyledString = new MutableStyledString("35-minute workout", [
130    {
131      start: 0,
132      length: 3,
133      styledKey: StyledStringKey.DECORATION,
134      styledValue: new DecorationStyle({type: TextDecorationType.LineThrough, color: Color.Red})
135    }
136    ]);
137    controller: TextController = new TextController();
138
139    async onPageShow() {
140      this.controller.setStyledString(this.mutableStyledString)
141    }
142
143    build() {
144      Column() {
145        // Display the styled string.
146        Text(undefined, { controller: this.controller })
147      }
148      .width('100%')
149    }
150  }
151  ```
152  ![StyledString_Decoration](figures/styled_string_decoration.png)
153
154- Creating and applying a **Text BaselineOffsetStyle** object
155
156  ```ts
157  import { LengthMetrics, LengthUnit } from '@kit.ArkUI'
158  // xxx.ets
159  @Entry
160  @Component
161  struct styled_string_demo5 {
162    mutableStyledString: MutableStyledString = new MutableStyledString("35-minute workout", [
163      {
164        start: 0,
165        length: 3,
166        styledKey: StyledStringKey.BASELINE_OFFSET,
167        styledValue: new BaselineOffsetStyle(LengthMetrics.px(20))
168      }
169    ]);
170    controller: TextController = new TextController();
171
172    async onPageShow() {
173      this.controller.setStyledString(this.mutableStyledString)
174    }
175
176    build() {
177      Column() {
178        // Display the styled string.
179        Text(undefined, { controller: this.controller })
180      }
181      .width('100%')
182    }
183  }
184  ```
185  ![StyledString_Baseline](figures/styled_string_baselineoffset.png)
186
187- Creating and applying a **LineHeightStyle** object
188
189  ```ts
190  import { LengthMetrics, LengthUnit } from '@kit.ArkUI'
191  // xxx.ets
192  @Entry
193  @Component
194  struct styled_string_demo6 {
195    mutableStyledString: MutableStyledString = new MutableStyledString("35-minute workout\nFighting\nAchieved", [
196      {
197        start: 8,
198        length: 3,
199        styledKey: StyledStringKey.LINE_HEIGHT,
200        styledValue: new LineHeightStyle(LengthMetrics.vp(50))
201      }
202    ]);
203    controller: TextController = new TextController();
204
205    async onPageShow() {
206      this.controller.setStyledString(this.mutableStyledString)
207    }
208
209    build() {
210      Column() {
211        // Display the styled string.
212        Text(undefined, { controller: this.controller })
213      }
214      .width('100%')
215      .margin({ top: 10 })
216    }
217  }
218  ```
219  ![StyledString_lineHeight](figures/styled_string_lineHeight.png)
220
221- Creating and applying a **LetterSpacingStyle** object
222
223  ```ts
224  import { LengthMetrics, LengthUnit } from '@kit.ArkUI'
225  // xxx.ets
226  @Entry
227  @Component
228  struct styled_string_demo7 {
229    mutableStyledString: MutableStyledString = new MutableStyledString("35-minute workout", [
230      {
231        start: 0,
232        length: 2,
233        styledKey: StyledStringKey.LETTER_SPACING,
234        styledValue: new LetterSpacingStyle(new LengthMetrics(20, LengthUnit.VP))
235      }
236    ]);
237    controller: TextController = new TextController();
238
239    async onPageShow() {
240      this.controller.setStyledString(this.mutableStyledString)
241    }
242
243    build() {
244      Column() {
245        // Display the styled string.
246        Text(undefined, { controller: this.controller })
247      }
248      .width('100%')
249    }
250  }
251  ```
252  ![StyledString_letterSpacing](figures/styled_string_letterspacing.png)
253
254## Setting the Paragraph Style
255
256You can set the paragraph style using [ParagraphStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#paragraphstyle). The figure below shows how to divide paragraphs in the text, with each paragraph ending with a newline character \n.
257
258![paragraphs](figures/styledstringParagraphs.png)
259
260The following example shows how to create and apply a paragraph style. The style is applied to the start, end or any position within a paragraph; it does not apply to non-paragraph areas.
261
262  ```ts
263  import { LengthMetrics } from '@kit.ArkUI'
264  titleParagraphStyleAttr: ParagraphStyle = new ParagraphStyle({ textAlign: TextAlign.Center });
265  // Create a paragraph style for a 15 vp first-line text indent.
266  paragraphStyleAttr1: ParagraphStyle = new ParagraphStyle({ textIndent: LengthMetrics.vp(15) });
267  // Line height style object
268  lineHeightStyle1: LineHeightStyle= new LineHeightStyle(new LengthMetrics(24));
269  // Create a paragraph style object paragraphStyledString1.
270  paragraphStyledString1: MutableStyledString = new MutableStyledString("Paragraph Title\nFirst paragraph starts 0123456789 First paragraph ends.", [
271    {
272      start: 0,
273      length: 4,
274      styledKey: StyledStringKey.PARAGRAPH_STYLE,
275      styledValue: this.titleParagraphStyleAttr
276    },
277    {
278      start: 0,
279      length: 4,
280      styledKey: StyledStringKey.LINE_HEIGHT,
281      styledValue: new LineHeightStyle(new LengthMetrics(50))
282    },{
283    start: 0,
284    length: 4,
285    styledKey: StyledStringKey.FONT,
286    styledValue: new TextStyle({ fontSize: LengthMetrics.vp(24), fontWeight: FontWeight.Bolder })
287  },
288    {
289      start: 5,
290      length: 3,
291      styledKey: StyledStringKey.PARAGRAPH_STYLE,
292      styledValue: this.paragraphStyleAttr1
293    },
294    {
295      start: 5,
296      length: 20,
297      styledKey: StyledStringKey.LINE_HEIGHT,
298      styledValue: this.lineHeightStyle1
299    }
300  ]);
301  ```
302
303  In addition to presetting styles when creating a styled string, you can also clear the original styles and replace them with new ones later using the [replaceStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#replacestyle) API. After the replacement, you need to proactively trigger an update to the bound styled string on the attached text component's controller.
304
305  ```ts
306  import { LengthMetrics } from '@kit.ArkUI'
307  // Set the maximum number of lines and text overflow mode for the paragraph, without setting the indent.
308  paragraphStyleAttr3: ParagraphStyle = new ParagraphStyle({ textAlign: TextAlign.End, maxLines: 1, wordBreak: WordBreak.BREAK_ALL, overflow: TextOverflow.Ellipsis});
309  // Later in the code, trigger an update to the paragraph style.
310  controller: TextController = new TextController();
311  this.paragraphStyledString1.replaceStyle({
312    start: 5,
313    length: 3,
314    styledKey: StyledStringKey.PARAGRAPH_STYLE,
315    styledValue: this.paragraphStyleAttr3
316  })
317  this.controller.setStyledString(this.paragraphStyledString1)
318  ```
319
320## Using Images
321
322You can add images using [ImageAttachment](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#imageattachment).
323
324The following example shows how to attach images and text to the same **MutableStyledString** object for mixed display of text and images.
325
326  ```ts
327  // xxx.ets
328  import { image } from '@kit.ImageKit'
329  import { LengthMetrics } from '@kit.ArkUI'
330
331  @Entry
332  @Component
333  struct styled_string_demo4 {
334    @State message: string = 'Hello World'
335    imagePixelMap: image.PixelMap | undefined = undefined
336    @State imagePixelMap3: image.PixelMap | undefined = undefined
337    mutableStr: MutableStyledString = new MutableStyledString('123');
338    controller: TextController = new TextController();
339    mutableStr2: MutableStyledString = new MutableStyledString('This is set decoration line style to the mutableStr2', [{
340      start: 0,
341      length: 15,
342      styledKey: StyledStringKey.DECORATION,
343      styledValue: new DecorationStyle({
344        type: TextDecorationType.Overline,
345        color: Color.Orange,
346        style: TextDecorationStyle.DOUBLE
347      })
348    }])
349
350    async aboutToAppear() {
351      console.info("aboutToAppear initial imagePixelMap")
352      this.imagePixelMap = await this.getPixmapFromMedia($r('app.media.sea'))
353    }
354
355    private async getPixmapFromMedia(resource: Resource) {
356      let unit8Array = await this.getUIContext().getHostContext()?.resourceManager?.getMediaContent({
357        bundleName: resource.bundleName,
358        moduleName: resource.moduleName,
359        id: resource.id
360      })
361      let imageSource = image.createImageSource(unit8Array?.buffer?.slice(0, unit8Array?.buffer?.byteLength))
362      let createPixelMap: image.PixelMap = await imageSource.createPixelMap({
363        desiredPixelFormat: image.PixelMapFormat.RGBA_8888
364      })
365      await imageSource.release()
366      return createPixelMap
367    }
368
369    leadingMarginValue: ParagraphStyle = new ParagraphStyle({ leadingMargin: LengthMetrics.vp(5)})
370    // Line height style object
371    lineHeightStyle1: LineHeightStyle= new LineHeightStyle(new LengthMetrics(24));
372    //Bold style
373    boldTextStyle: TextStyle = new TextStyle({ fontWeight: FontWeight.Bold });
374    // Create a paragraph style object paragraphStyledString1.
375    paragraphStyledString1: MutableStyledString = new MutableStyledString("\n30 HD prints\nCYN5.15 off Limited offer", [
376      {
377        start: 0,
378        length: 28,
379        styledKey: StyledStringKey.PARAGRAPH_STYLE,
380        styledValue: this.leadingMarginValue
381      },
382      {
383        start: 14,
384        length: 9,
385        styledKey: StyledStringKey.FONT,
386        styledValue: new TextStyle({ fontSize: LengthMetrics.vp(14), fontColor: '#B22222' })
387      },
388      {
389        start: 24,
390        length: 4,
391        styledKey: StyledStringKey.FONT,
392        styledValue: new TextStyle({ fontSize: LengthMetrics.vp(14), fontWeight: FontWeight.Lighter })
393      },
394      {
395        start: 11,
396        length: 4,
397        styledKey: StyledStringKey.LINE_HEIGHT,
398        styledValue: this.lineHeightStyle1
399      }
400    ]);
401    paragraphStyledString2: MutableStyledString = new MutableStyledString("\n¥16.21 3000+ reviews", [
402      {
403        start: 0,
404        length: 5,
405        styledKey: StyledStringKey.PARAGRAPH_STYLE,
406        styledValue: this.leadingMarginValue
407      },
408      {
409        start: 0,
410        length: 4,
411        styledKey: StyledStringKey.LINE_HEIGHT,
412        styledValue: new LineHeightStyle(new LengthMetrics(60))
413      },
414      {
415        start: 0,
416        length: 7,
417        styledKey: StyledStringKey.FONT,
418        styledValue: this.boldTextStyle
419      },
420      {
421        start: 1,
422        length: 1,
423        styledKey: StyledStringKey.FONT,
424        styledValue: new TextStyle({ fontSize: LengthMetrics.vp(18) })
425      },
426      {
427        start: 2,
428        length: 2,
429        styledKey: StyledStringKey.FONT,
430        styledValue: new TextStyle({ fontSize: LengthMetrics.vp(36) })
431      },
432      {
433        start: 4,
434        length: 3,
435        styledKey: StyledStringKey.FONT,
436        styledValue: new TextStyle({ fontSize: LengthMetrics.vp(20) })
437      },
438      {
439        start: 7,
440        length: 9,
441        styledKey: StyledStringKey.FONT,
442        styledValue: new TextStyle({ fontColor: Color.Grey, fontSize: LengthMetrics.vp(14)})
443      }
444    ])
445
446    build() {
447      Row() {
448        Column({ space: 10 }) {
449          Text(undefined, { controller: this.controller })
450            .copyOption(CopyOptions.InApp)
451            .draggable(true)
452            .backgroundColor('#FFFFFF')
453            .borderRadius(5)
454
455          Button('View Product Details')
456            .onClick(() => {
457              if (this.imagePixelMap !== undefined) {
458                this.mutableStr = new MutableStyledString(new ImageAttachment({
459                  value: this.imagePixelMap,
460                  size: { width: 180, height: 160 },
461                  verticalAlign: ImageSpanAlignment.BASELINE,
462                  objectFit: ImageFit.Fill
463                }))
464                this.paragraphStyledString1.appendStyledString(this.paragraphStyledString2)
465                this.mutableStr.appendStyledString(this.paragraphStyledString1)
466                this.controller.setStyledString(this.mutableStr)
467              }
468            })
469        }
470        .width('100%')
471      }
472      .height('100%')
473      .backgroundColor('#F8F8FF')
474    }
475  }
476  ```
477  ![StyledString_ImageAttachment](figures/StyledStringImageAttachment.png)
478
479## Setting Events
480
481You can use [GestureStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#gesturestyle) to set up **onClick** and **onLongPress** events to enable text to respond to click and long-press actions.
482
483In addition to initializing styled strings with initial style objects, you can also use the [setStyle](../reference/apis-arkui/arkui-ts/ts-universal-styled-string.md#setstyle) API to overlay new styles or update existing ones. After making changes, you need to manually trigger an update of the bound styled string on the attached text component's controller.
484
485  ```ts
486import { drawing } from '@kit.ArkGraphics2D';
487
488class MyCustomSpan extends CustomSpan {
489  constructor(word: string, width: number, height: number, fontSize: number) {
490    super();
491    this.word = word;
492    this.width = width;
493    this.height = height;
494    this.fontSize = fontSize;
495  }
496
497  onMeasure(measureInfo: CustomSpanMeasureInfo): CustomSpanMetrics {
498    return { width: this.width, height: this.height }
499  }
500
501  onDraw(context: DrawContext, options: CustomSpanDrawInfo) {
502    let canvas = context.canvas;
503
504    const brush = new drawing.Brush();
505    brush.setColor({ alpha: 255, red: 0, green: 0, blue: 0 })
506    const font = new drawing.Font()
507    font.setSize(vp2px(this.fontSize))
508    const textBlob = drawing.TextBlob.makeFromString(this.word.substring(0, 5), font, drawing.TextEncoding.TEXT_ENCODING_UTF8)
509    canvas.attachBrush(brush)
510
511    this.onDrawRectByRadius(context, options.x, options.x + vp2px(this.width), options.lineTop, options.lineBottom, 20)
512    brush.setColor({ alpha: 255, red: 255, green: 255, blue: 255 })
513    canvas.attachBrush(brush)
514    canvas.drawTextBlob(textBlob, options.x, options.lineBottom - 30)
515    brush.setColor({ alpha: 255, red: 255, green: 228 , blue: 196 })
516    canvas.attachBrush(brush)
517    const textBlob1 = drawing.TextBlob.makeFromString(this.word.substring(5), font, drawing.TextEncoding.TEXT_ENCODING_UTF8)
518    canvas.drawTextBlob(textBlob1, options.x + vp2px(100), options.lineBottom - 30)
519
520    canvas.detachBrush()
521  }
522  onDrawRectByRadius(context: DrawContext, left: number, right: number, top: number, bottom: number, radius: number) {
523    let canvas = context.canvas
524    let path = new drawing.Path()
525
526    // Draw a rectangle with rounded corners.
527    path.moveTo(left  + radius, top)
528    path.lineTo(right - radius, top)
529    path.arcTo(right - 2 * radius, top, right, top + 2 * radius, 270, 90)
530    path.lineTo(right, bottom - radius)
531    path.arcTo(right - 2 * radius, bottom - 2 * radius, right, bottom, 0, 90)
532
533    path.lineTo(left + 2 * radius, bottom)
534    path.arcTo(left, bottom - 2 * radius, left + 2 * radius, bottom, 90, 90)
535    path.lineTo(left, top + 2 * radius)
536    path.arcTo(left, top, left + 2 * radius, top + 2 * radius, 180, 90)
537
538    canvas.drawPath(path)
539  }
540  setWord(word: string) {
541    this.word = word;
542  }
543
544  width: number = 160
545  word: string = "drawing"
546  height: number = 10
547  fontSize: number = 16
548}
549
550@Entry
551@Component
552struct styled_string_demo6 {
553  customSpan3: MyCustomSpan = new MyCustomSpan("99VIP88%off", 200, 40, 30)
554  textStyle: MutableStyledString = new MutableStyledString("123");
555  textController: TextController = new TextController()
556  isPageShow: boolean = true
557
558  async onPageShow() {
559    if (!this.isPageShow) {
560      return
561    }
562    this.isPageShow = false
563    this.textController.setStyledString(new StyledString(this.customSpan3))
564  }
565
566  build() {
567    Row() {
568      Column() {
569        Text(undefined, { controller: this.textController })
570          .copyOption(CopyOptions.InApp)
571          .fontSize(30)
572      }
573      .width('100%')
574    }
575    .height('100%')
576  }
577}
578  ```
579![CustomSpanDemo](figures/StyledString_CustomSpan_Scene.PNG)
580
581## Example
582
583This example shows how to implement an expired membership notification using **ParagraphStyle**, **LineHeightStyle**, and **TextStyle** objects.
584
585```ts
586import { LengthMetrics } from '@kit.ArkUI';
587
588@Entry
589@Component
590struct Index {
591  alignCenterParagraphStyleAttr: ParagraphStyle = new ParagraphStyle({ textAlign: TextAlign.Center });
592  // Line height style object
593  lineHeightStyle1: LineHeightStyle= new LineHeightStyle(LengthMetrics.vp(24));
594  //Bold style
595  boldTextStyle: TextStyle = new TextStyle({ fontWeight: FontWeight.Bold });
596  // Create a paragraph style object paragraphStyledString1.
597  paragraphStyledString1: MutableStyledString = new MutableStyledString("Diamond Membership expired\nRenew to keep your perks ", [
598    {
599      start: 0,
600      length: 4,
601      styledKey: StyledStringKey.PARAGRAPH_STYLE,
602      styledValue: this.alignCenterParagraphStyleAttr
603    },
604    {
605      start: 0,
606      length: 4,
607      styledKey: StyledStringKey.LINE_HEIGHT,
608      styledValue: new LineHeightStyle(LengthMetrics.vp(40))
609    },
610    {
611      start: 11,
612      length: 14,
613      styledKey: StyledStringKey.FONT,
614      styledValue: new TextStyle({ fontSize: LengthMetrics.vp(14), fontColor: Color.Grey })
615    },
616    {
617      start: 11,
618      length: 4,
619      styledKey: StyledStringKey.PARAGRAPH_STYLE,
620      styledValue: this.alignCenterParagraphStyleAttr
621    },
622    {
623      start: 11,
624      length: 4,
625      styledKey: StyledStringKey.LINE_HEIGHT,
626      styledValue: this.lineHeightStyle1
627    }
628  ]);
629  paragraphStyledString2: MutableStyledString = new MutableStyledString("\n¥4.88¥15", [
630    {
631      start: 0,
632      length: 4,
633      styledKey: StyledStringKey.PARAGRAPH_STYLE,
634      styledValue: this.alignCenterParagraphStyleAttr
635    },
636    {
637      start: 0,
638      length: 4,
639      styledKey: StyledStringKey.LINE_HEIGHT,
640      styledValue: new LineHeightStyle(LengthMetrics.vp(60))
641    },
642    {
643      start: 0,
644      length: 6,
645      styledKey: StyledStringKey.FONT,
646      styledValue: this.boldTextStyle
647    },
648    {
649      start: 1,
650      length: 1,
651      styledKey: StyledStringKey.FONT,
652      styledValue: new TextStyle({ fontSize: LengthMetrics.vp(18)})
653    },
654    {
655      start: 2,
656      length: 4,
657      styledKey: StyledStringKey.FONT,
658      styledValue: new TextStyle({ fontSize: LengthMetrics.vp(40)})
659    },
660    {
661      start: 6,
662      length: 3,
663      styledKey: StyledStringKey.FONT,
664      styledValue: new TextStyle({ fontColor: Color.Grey, fontSize: LengthMetrics.vp(14)})
665    },
666    {
667      start: 6,
668      length: 3,
669      styledKey: StyledStringKey.DECORATION,
670      styledValue: new DecorationStyle({ type: TextDecorationType.LineThrough, color: Color.Grey })
671    }
672  ])
673  paragraphStyledString3: MutableStyledString = new MutableStyledString("\nOffer ends in 02:06", [
674    {
675      start: 0,
676      length: 4,
677      styledKey: StyledStringKey.PARAGRAPH_STYLE,
678      styledValue: this.alignCenterParagraphStyleAttr
679    },
680    {
681      start: 0,
682      length: 4,
683      styledKey: StyledStringKey.LINE_HEIGHT,
684      styledValue: new LineHeightStyle(LengthMetrics.vp(30))
685    },
686    {
687      start: 1,
688      length: 2,
689      styledKey: StyledStringKey.FONT,
690      styledValue: new TextStyle({ fontColor: '#FFD700', fontWeight: FontWeight.Bold })
691    },
692    {
693      start: 4,
694      length: 2,
695      styledKey: StyledStringKey.FONT,
696      styledValue: new TextStyle({ fontColor: '#FFD700', fontWeight: FontWeight.Bold })
697    }
698  ])
699  controller: TextController = new TextController();
700
701  build() {
702    Row() {
703      Column( { space : 5 }) {
704        Text(undefined, { controller: this.controller })
705          .width(240)
706          .copyOption(CopyOptions.InApp)
707          .draggable(true)
708          .onAppear(()=>{
709            this.paragraphStyledString2.appendStyledString(this.paragraphStyledString3)
710            this.paragraphStyledString1.appendStyledString(this.paragraphStyledString2)
711            this.controller.setStyledString(this.paragraphStyledString1)
712          })
713
714        Button("Renew")
715          .width(200)
716          .fontColor(Color.White)
717          .fontSize(18)
718          .backgroundColor('#3CB371')
719          .margin({ bottom: 10 })
720      }
721      .borderWidth(1).borderColor('#FFDEAD')
722      .margin({ left: 10 })
723    }
724    .height('60%')
725  }
726}
727```
728![StyledString_SceneDemo](figures/styledString_sceneDemo.png)
729