1# \@Builder装饰器:自定义构建函数 2 3ArkUI提供了一种轻量的UI元素复用机制\@Builder,该自定义组件内部UI结构固定,仅与使用方进行数据传递,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。 4 5为了简化语言,我们将\@Builder装饰的函数也称为“自定义构建函数”。 6 7 8> **说明:** 9> 10> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。 11> 12> 从API version 11开始,该装饰器支持在原子化服务中使用。 13 14## 限制条件 15 16- \@Builder通过按引用传递的方式传入参数,才会触发动态渲染UI,并且参数只能是一个。 17 18- \@Builder如果传入的参数是两个或两个以上,不会触发动态渲染UI。 19 20- \@Builder传入的参数中同时包含按值传递和按引用传递两种方式,不会触发动态渲染UI。 21 22- \@Builder的参数必须按照对象字面量的形式,把所需要的属性一一传入,才会触发动态渲染UI。 23 24## 装饰器使用说明 25 26### 私有自定义构建函数 27 28定义的语法: 29 30```ts 31@Builder MyBuilderFunction() {} 32``` 33 34使用方法: 35 36```ts 37this.MyBuilderFunction() 38``` 39 40- 允许在自定义组件内定义一个或多个@Builder方法,该方法被认为是该组件的私有、特殊类型的成员函数。 41 42- 私有自定义构建函数允许在自定义组件内、build方法和其他自定义构建函数中调用。 43 44- 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递。 45 46 47### 全局自定义构建函数 48 49定义的语法: 50 51```ts 52@Builder function MyGlobalBuilderFunction() { ... } 53``` 54 55使用方法: 56 57```ts 58MyGlobalBuilderFunction() 59``` 60 61- 如果不涉及组件状态变化,建议使用全局的自定义构建方法。 62 63- 全局自定义构建函数允许在build方法和其他自定义构建函数中调用。 64 65 66## 参数传递规则 67 68自定义构建函数的参数传递有[按值传递](#按值传递参数)和[按引用传递](#按引用传递参数)两种,均需遵守以下规则: 69 70- 参数的类型必须与参数声明的类型一致,不允许undefined、null和返回undefined、null的表达式。 71 72- 在@Builder修饰的函数内部,不允许改变参数值。 73 74- \@Builder内UI语法遵循[UI语法规则](arkts-create-custom-components.md#build函数)。 75 76- 只有传入一个参数,且参数需要直接传入对象字面量才会按引用传递该参数,其余传递方式均为按值传递。 77 78 79### 按引用传递参数 80 81按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起\@Builder方法内的UI刷新。 82 83```ts 84class Tmp { 85 paramA1: string = '' 86} 87 88@Builder function overBuilder(params: Tmp) { 89 Row() { 90 Text(`UseStateVarByReference: ${params.paramA1} `) 91 } 92} 93@Entry 94@Component 95struct Parent { 96 @State label: string = 'Hello'; 97 build() { 98 Column() { 99 // Pass the this.label reference to the overBuilder component when the overBuilder component is called in the Parent component. 100 overBuilder({ paramA1: this.label }) 101 Button('Click me').onClick(() => { 102 // After Click me is clicked, the UI text changes from Hello to ArkUI. 103 this.label = 'ArkUI'; 104 }) 105 } 106 } 107} 108``` 109 110按引用传递参数时,如果在\@Builder方法内调用自定义组件,ArkUI提供[$$](arkts-two-way-sync.md)作为按引用传递参数的范式。 111 112```ts 113class Tmp { 114 paramA1: string = '' 115} 116 117@Builder function overBuilder($$: Tmp) { 118 Row() { 119 Column() { 120 Text(`overBuilder===${$$.paramA1}`) 121 HelloComponent({message: $$.paramA1}) 122 } 123 } 124} 125 126@Component 127struct HelloComponent { 128 @Prop message: string; 129 130 build() { 131 Row() { 132 Text(`HelloComponent===${this.message}`) 133 } 134 } 135} 136 137@Entry 138@Component 139struct Parent { 140 @State label: string = 'Hello'; 141 build() { 142 Column() { 143 // Pass the this.label reference to the overBuilder component when the overBuilder component is called in the Parent component. 144 overBuilder({paramA1: this.label}) 145 Button('Click me').onClick(() => { 146 // After Click me is clicked, the UI text changes from Hello to ArkUI. 147 this.label = 'ArkUI'; 148 }) 149 } 150 } 151} 152``` 153 154### 按值传递参数 155 156调用\@Builder装饰的函数默认按值传递。当传递的参数为状态变量时,状态变量的改变不会引起\@Builder方法内的UI刷新。所以当使用状态变量的时候,推荐使用[按引用传递](#按引用传递参数)。 157 158```ts 159@Builder function overBuilder(paramA1: string) { 160 Row() { 161 Text(`UseStateVarByValue: ${paramA1} `) 162 } 163} 164@Entry 165@Component 166struct Parent { 167 @State label: string = 'Hello'; 168 build() { 169 Column() { 170 overBuilder(this.label) 171 } 172 } 173} 174``` 175 176使用按值传递的方式,在@ComponentV2装饰器修饰的自定义组件里配合使用@ObservedV2和@Trace装饰器可以实现刷新UI功能。 177 178【正例】 179 180在@ComponentV2装饰中,只有使用@ObservedV2修饰的ParamTmp类和@Trace修饰的count属性才可以触发UI的刷新。 181 182```ts 183@ObservedV2 184class ParamTmp { 185 @Trace count : number = 0; 186} 187 188@Builder 189function renderText(param: ParamTmp) { 190 Column() { 191 Text(`param : ${param.count}`) 192 .fontSize(20) 193 .fontWeight(FontWeight.Bold) 194 } 195} 196 197@Builder 198function renderMap(paramMap: Map<string,number>) { 199 Text(`paramMap : ${paramMap.get('name')}`) 200 .fontSize(20) 201 .fontWeight(FontWeight.Bold) 202} 203 204@Builder 205function renderSet(paramSet: Set<number>) { 206 Text(`paramSet : ${paramSet.size}`) 207 .fontSize(20) 208 .fontWeight(FontWeight.Bold) 209} 210 211@Builder 212function renderNumberArr(paramNumArr: number[]) { 213 Text(`paramNumArr : ${paramNumArr[0]}`) 214 .fontSize(20) 215 .fontWeight(FontWeight.Bold) 216} 217 218@Entry 219@ComponentV2 220struct PageBuilder { 221 @Local builderParams: ParamTmp = new ParamTmp(); 222 @Local map_value: Map<string,number> = new Map(); 223 @Local set_value: Set<number> = new Set([0]); 224 @Local numArr_value: number[] = [0]; 225 private progressTimer: number = -1; 226 227 aboutToAppear(): void { 228 this.progressTimer = setInterval(() => { 229 if (this.builderParams.count < 100) { 230 this.builderParams.count += 5; 231 this.map_value.set('name', this.builderParams.count); 232 this.set_value.add(this.builderParams.count); 233 this.numArr_value[0] = this.builderParams.count; 234 } else { 235 clearInterval(this.progressTimer) 236 } 237 }, 500); 238 } 239 240 @Builder 241 localBuilder() { 242 Column() { 243 Text(`localBuilder : ${this.builderParams.count}`) 244 .fontSize(20) 245 .fontWeight(FontWeight.Bold) 246 } 247 } 248 249 build() { 250 Column() { 251 this.localBuilder() 252 Text(`builderParams :${this.builderParams.count}`) 253 .fontSize(20) 254 .fontWeight(FontWeight.Bold) 255 renderText(this.builderParams) 256 renderText({ count: this.builderParams.count }) 257 renderMap(this.map_value) 258 renderSet(this.set_value) 259 renderNumberArr(this.numArr_value) 260 } 261 .width('100%') 262 .height('100%') 263 } 264} 265``` 266 267【反例】 268 269在@ComponentV2装饰的自定义组件中,使用简单数据类型不可以触发UI的刷新。 270 271```ts 272@ObservedV2 273class ParamTmp { 274 @Trace count : number = 0; 275} 276 277@Builder 278function renderNumber(paramNum: number) { 279 Text(`paramNum : ${paramNum}`) 280 .fontSize(30) 281 .fontWeight(FontWeight.Bold) 282} 283 284@Entry 285@ComponentV2 286struct PageBuilder { 287 @Local class_value: ParamTmp = new ParamTmp(); 288 // 此处使用简单数据类型不支持刷新UI的能力。 289 @Local num_value: number = 0; 290 private progressTimer: number = -1; 291 292 aboutToAppear(): void { 293 this.progressTimer = setInterval(() => { 294 if (this.class_value.count < 100) { 295 this.class_value.count += 5; 296 this.num_value += 5; 297 } else { 298 clearInterval(this.progressTimer) 299 } 300 }, 500); 301 } 302 303 build() { 304 Column() { 305 renderNumber(this.num_value) 306 } 307 .width('100%') 308 .height('100%') 309 .padding(50) 310 } 311} 312``` 313 314## 使用场景 315 316### 自定义组件内使用自定义构建函数 317 318创建私有的\@Builder方法,在Column里面使用this.builder()方式调用,通过aboutToAppear生命周期函数和按钮的点击事件改变builder_value的内容,实现动态渲染UI。 319 320```ts 321@Entry 322@Component 323struct PrivateBuilder { 324 @State builder_value: string = 'Hello'; 325 326 @Builder builder() { 327 Column(){ 328 Text(this.builder_value) 329 .fontSize(30) 330 .fontWeight(FontWeight.Bold) 331 } 332 } 333 334 aboutToAppear(): void { 335 setTimeout(() => { 336 this.builder_value = 'Hello World'; 337 },3000) 338 } 339 340 build() { 341 Row() { 342 Column() { 343 Text(this.builder_value) 344 .fontSize(30) 345 .fontWeight(FontWeight.Bold) 346 this.builder() 347 Button('点击改变builder_value内容') 348 .onClick(() => { 349 this.builder_value ='builder_value被点击了' 350 }) 351 } 352 } 353 } 354} 355``` 356 357### 使用全局自定义构建函数 358 359创建全局的\@Builder方法,在Column里面使用overBuilder()方式调用,通过以对象字面量的形式传递参数,无论是简单类型还是复杂类型,值的改变都会引起UI界面的刷新。 360 361```ts 362class ChildTmp { 363 val: number = 1; 364} 365 366class Tmp { 367 str_value: string = 'Hello'; 368 num_value: number = 0; 369 tmp_value: ChildTmp = new ChildTmp(); 370 arrayTmp_value: Array<ChildTmp> = []; 371} 372 373@Builder function overBuilder(param: Tmp) { 374 Column() { 375 Text(`str_value: ${param.str_value}`) 376 Text(`num_value: ${param.num_value}`) 377 Text(`tmp_value: ${param.tmp_value.val}`) 378 ForEach(param.arrayTmp_value, (item: ChildTmp) => { 379 Text(`arrayTmp_value: ${item.val}`) 380 }, (item: ChildTmp) => JSON.stringify(item)) 381 } 382} 383 384@Entry 385@Component 386struct Parent { 387 @State objParam: Tmp = new Tmp(); 388 build() { 389 Column() { 390 Text('通过调用@Builder渲染UI界面') 391 .fontSize(20) 392 overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value, tmp_value: this.objParam.tmp_value, arrayTmp_value: this.objParam.arrayTmp_value}) 393 Line() 394 .width('100%') 395 .height(10) 396 .backgroundColor('#000000').margin(10) 397 Button('点击改变参数值').onClick(() => { 398 this.objParam.str_value = 'Hello World'; 399 this.objParam.num_value = 1; 400 this.objParam.tmp_value.val = 8; 401 const child_value: ChildTmp = { 402 val: 2 403 } 404 this.objParam.arrayTmp_value.push(child_value) 405 }) 406 } 407 } 408} 409``` 410 411### 修改装饰器修饰的变量触发UI刷新 412 413此种方式是使用了装饰器的特性,监听值的改变触发UI刷新,不通过\@Builder传递参数。 414 415```ts 416class Tmp { 417 str_value: string = 'Hello'; 418} 419 420@Entry 421@Component 422struct Parent { 423 @State objParam: Tmp = new Tmp(); 424 @State label: string = 'World'; 425 426 @Builder privateBuilder() { 427 Column() { 428 Text(`wrapBuilder str_value: ${this.objParam.str_value}`) 429 Text(`wrapBuilder num: ${this.label}`) 430 } 431 } 432 433 build() { 434 Column() { 435 Text('通过调用@Builder渲染UI界面') 436 .fontSize(20) 437 this.privateBuilder() 438 Line() 439 .width('100%') 440 .height(10) 441 .backgroundColor('#000000').margin(10) 442 Button('点击改变参数值').onClick(() => { 443 this.objParam.str_value = 'str_value Hello World'; 444 this.label = 'label Hello World' 445 }) 446 } 447 } 448} 449``` 450 451### 使用全局和局部的@Builder传入customBuilder类型 452 453```ts 454@Builder 455function overBuilder() { 456 Row() { 457 Text('全局 Builder') 458 .fontSize(30) 459 .fontWeight(FontWeight.Bold) 460 } 461} 462 463@Entry 464@Component 465struct customBuilderDemo { 466 @State arr: number[] = [0, 1, 2, 3, 4]; 467 468 @Builder privateBuilder() { 469 Row() { 470 Text('局部 Builder') 471 .fontSize(30) 472 .fontWeight(FontWeight.Bold) 473 } 474 } 475 476 build() { 477 Column() { 478 List({ space: 10 }) { 479 ForEach(this.arr, (item: number) => { 480 ListItem(){ 481 Text(`${item}`) 482 .width('100%') 483 .height(100) 484 .fontSize(16) 485 .textAlign(TextAlign.Center) 486 .borderRadius(10) 487 .backgroundColor(0xFFFFFF) 488 } 489 .swipeAction({ 490 start: { 491 builder: overBuilder() 492 }, 493 end: { 494 builder: () => { this.privateBuilder() } 495 } 496 }) 497 }, (item: string) => JSON.stringify(item)) 498 } 499 } 500 } 501} 502``` 503 504### 多层\@Builder方法嵌套使用 505 506在\@Builder方法内调用自定义组件或者其他\@Builder方法,ArkUI提供[$$](arkts-two-way-sync.md)作为按引用传递参数的范式。 507 508```ts 509class Tmp { 510 paramA1: string = ''; 511} 512 513@Builder function parentBuilder($$: Tmp) { 514 Row() { 515 Column() { 516 Text(`parentBuilder===${$$.paramA1}`) 517 .fontSize(30) 518 .fontWeight(FontWeight.Bold) 519 HelloComponent({message: $$.paramA1}) 520 childBuilder({paramA1: $$.paramA1}) 521 } 522 } 523} 524 525@Component 526struct HelloComponent { 527 @Prop message: string = ''; 528 529 build() { 530 Row() { 531 Text(`HelloComponent===${this.message}`) 532 .fontSize(30) 533 .fontWeight(FontWeight.Bold) 534 } 535 } 536} 537 538@Builder 539function childBuilder($$: Tmp) { 540 Row() { 541 Column() { 542 Text(`childBuilder===${$$.paramA1}`) 543 .fontSize(30) 544 .fontWeight(FontWeight.Bold) 545 HelloChildComponent({message: $$.paramA1}) 546 grandsonBuilder({paramA1: $$.paramA1}) 547 } 548 } 549} 550 551@Component 552struct HelloChildComponent { 553 @State message: string = ''; 554 build() { 555 Row() { 556 Text(`HelloChildComponent===${this.message}`) 557 .fontSize(30) 558 .fontWeight(FontWeight.Bold) 559 } 560 } 561} 562 563@Builder function grandsonBuilder($$: Tmp) { 564 Row() { 565 Column() { 566 Text(`grandsonBuilder===${$$.paramA1}`) 567 .fontSize(30) 568 .fontWeight(FontWeight.Bold) 569 HelloGrandsonComponent({message: $$.paramA1}) 570 } 571 } 572} 573 574@Component 575struct HelloGrandsonComponent { 576 @Prop message: string; 577 build() { 578 Row() { 579 Text(`HelloGrandsonComponent===${this.message}`) 580 .fontSize(30) 581 .fontWeight(FontWeight.Bold) 582 } 583 } 584} 585 586@Entry 587@Component 588struct Parent { 589 @State label: string = 'Hello'; 590 build() { 591 Column() { 592 parentBuilder({paramA1: this.label}) 593 Button('Click me').onClick(() => { 594 this.label = 'ArkUI'; 595 }) 596 } 597 } 598} 599``` 600 601### \@Builder函数联合V2装饰器使用 602 603使用全局@Builder和局部@Builder在@ComponentV2修饰的自定义组件中调用,修改相关变量触发UI刷新。 604 605```ts 606@ObservedV2 607class Info { 608 @Trace name: string = ''; 609 @Trace age: number = 0; 610} 611 612@Builder 613function overBuilder(param: Info) { 614 Column() { 615 Text(`全局@Builder name :${param.name}`) 616 .fontSize(30) 617 .fontWeight(FontWeight.Bold) 618 Text(`全局@Builder age :${param.age}`) 619 .fontSize(30) 620 .fontWeight(FontWeight.Bold) 621 } 622} 623 624@ComponentV2 625struct ChildPage { 626 @Require @Param childInfo: Info; 627 build() { 628 overBuilder({name: this.childInfo.name, age: this.childInfo.age}) 629 } 630} 631 632@Entry 633@ComponentV2 634struct ParentPage { 635 info1: Info = { name: "Tom", age: 25 }; 636 @Local info2: Info = { name: "Tom", age: 25 }; 637 638 @Builder 639 privateBuilder() { 640 Column() { 641 Text(`局部@Builder name :${this.info1.name}`) 642 .fontSize(30) 643 .fontWeight(FontWeight.Bold) 644 Text(`局部@Builder age :${this.info1.age}`) 645 .fontSize(30) 646 .fontWeight(FontWeight.Bold) 647 } 648 } 649 650 build() { 651 Column() { 652 Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1 653 .fontSize(30) 654 .fontWeight(FontWeight.Bold) 655 this.privateBuilder() // 调用局部@Builder 656 Line() 657 .width('100%') 658 .height(10) 659 .backgroundColor('#000000').margin(10) 660 Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text2 661 .fontSize(30) 662 .fontWeight(FontWeight.Bold) 663 overBuilder({ name: this.info2.name, age: this.info2.age}) // 调用全局@Builder 664 Line() 665 .width('100%') 666 .height(10) 667 .backgroundColor('#000000').margin(10) 668 Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1 669 .fontSize(30) 670 .fontWeight(FontWeight.Bold) 671 ChildPage({ childInfo: this.info1}) // 调用自定义组件 672 Line() 673 .width('100%') 674 .height(10) 675 .backgroundColor('#000000').margin(10) 676 Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text2 677 .fontSize(30) 678 .fontWeight(FontWeight.Bold) 679 ChildPage({ childInfo: this.info2}) // 调用自定义组件 680 Line() 681 .width('100%') 682 .height(10) 683 .backgroundColor('#000000').margin(10) 684 Button("change info1&info2") 685 .onClick(() => { 686 this.info1 = { name: "Cat", age: 18} // Text1不会刷新,原因是没有装饰器修饰监听不到值的改变。 687 this.info2 = { name: "Cat", age: 18} // Text2会刷新,原因是有装饰器修饰,可以监听到值的改变。 688 }) 689 } 690 } 691} 692``` 693 694## 常见问题 695 696### \@Builder存在两个或者两个以上参数 697 698当参数存在两个或者两个以上的时候,就算通过对象字面量的形式传递,值的改变也不会引起UI刷新。 699 700【反例】 701 702```ts 703class GlobalTmp { 704 str_value: string = 'Hello'; 705} 706 707@Builder function overBuilder(param: GlobalTmp, num: number) { 708 Column() { 709 Text(`str_value: ${param.str_value}`) 710 Text(`num: ${num}`) 711 } 712} 713 714@Entry 715@Component 716struct Parent { 717 @State objParam: GlobalTmp = new GlobalTmp(); 718 @State num: number = 0; 719 build() { 720 Column() { 721 Text('通过调用@Builder渲染UI界面') 722 .fontSize(20) 723 overBuilder({str_value: this.objParam.str_value}, this.num) // 此处出现问题,使用了两个参数。 724 Line() 725 .width('100%') 726 .height(10) 727 .backgroundColor('#000000').margin(10) 728 Button('点击改变参数值').onClick(() => { 729 this.objParam.str_value = 'Hello World'; 730 this.num = 1; 731 }) 732 } 733 } 734} 735``` 736 737【反例】 738 739```ts 740class GlobalTmp { 741 str_value: string = 'Hello'; 742} 743class SecondTmp { 744 num_value: number = 0; 745} 746@Builder function overBuilder(param: GlobalTmp, num: SecondTmp) { 747 Column() { 748 Text(`str_value: ${param.str_value}`) 749 Text(`num: ${num.num_value}`) 750 } 751} 752 753@Entry 754@Component 755struct Parent { 756 @State strParam: GlobalTmp = new GlobalTmp(); 757 @State numParam: SecondTmp = new SecondTmp(); 758 build() { 759 Column() { 760 Text('通过调用@Builder渲染UI界面') 761 .fontSize(20) 762 overBuilder({str_value: this.strParam.str_value}, {num_value: this.numParam.num_value}) // 此处出现问题,使用了两个参数。 763 Line() 764 .width('100%') 765 .height(10) 766 .backgroundColor('#000000').margin(10) 767 Button('点击改变参数值').onClick(() => { 768 this.strParam.str_value = 'Hello World'; 769 this.numParam.num_value = 1; 770 }) 771 } 772 } 773} 774``` 775 776\@Builder只接受一个参数,当传入一个参数的时候,通过对象字面量的形式传递,值的改变会引起UI的刷新。 777 778【正例】 779 780```ts 781class GlobalTmp { 782 str_value: string = 'Hello'; 783 num_value: number = 0; 784} 785@Builder function overBuilder(param: GlobalTmp) { 786 Column() { 787 Text(`str_value: ${param.str_value}`) 788 Text(`num: ${param.num_value}`) 789 } 790} 791 792@Entry 793@Component 794struct Parent { 795 @State objParam: GlobalTmp = new GlobalTmp(); 796 build() { 797 Column() { 798 Text('通过调用@Builder渲染UI界面') 799 .fontSize(20) 800 overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value}) 801 Line() 802 .width('100%') 803 .height(10) 804 .backgroundColor('#000000').margin(10) 805 Button('点击改变参数值').onClick(() => { 806 this.objParam.str_value = 'Hello World'; 807 this.objParam.num_value = 1; 808 }) 809 } 810 } 811} 812``` 813 814### \@Builder函数里面使用的组件没有根节点包裹 815 816在\@Builder函数里使用if判断语句时,创建的组件没有被Column/Row(根节点)包裹,会出现组件创建不出来的情况。 817 818【反例】 819 820```ts 821const showComponent: boolean = true; 822@Builder function OverlayNode() { 823 // 没有Column或者Row根节点导致Text组件没有创建 824 if (showComponent) { 825 Text("This is overlayNode Blue page") 826 .fontSize(20) 827 .fontColor(Color.Blue) 828 .height(100) 829 .textAlign(TextAlign.End) 830 } else { 831 Text("This is overlayNode Red page") 832 .fontSize(20) 833 .fontColor(Color.Red) 834 } 835} 836 837@Entry 838@Component 839struct OverlayExample { 840 841 build() { 842 RelativeContainer() { 843 Text('Hello World') 844 .overlay(OverlayNode(), { align: Alignment.Center}) 845 } 846 .height('100%') 847 .width('100%') 848 } 849} 850``` 851 852【正例】 853 854```ts 855const showComponent: boolean = true; 856@Builder function OverlayNode() { 857 Column() { 858 if (showComponent) { 859 Text("This is overlayNode Blue page") 860 .fontSize(20) 861 .fontColor(Color.Blue) 862 .height(100) 863 .textAlign(TextAlign.End) 864 } else { 865 Text("This is overlayNode Red page") 866 .fontSize(20) 867 .fontColor(Color.Red) 868 } 869 } 870} 871 872@Entry 873@Component 874struct OverlayExample { 875 876 build() { 877 RelativeContainer() { 878 Text('Hello World') 879 .overlay(OverlayNode(), { align: Alignment.Center}) 880 } 881 .height('100%') 882 .width('100%') 883 } 884} 885```