1# ArkUI组件开发常见问题(ArkTS)
2
3
4## 自定义弹窗能否在ts文件中定义和使用(API 9)
5
6自定义弹窗的定义和初始化需要用到属于ArkTS语法内容,必须在ets后缀文件中定义使用,不能在ts后缀文件中定义使用。
7
8**参考链接**
9
10[自定义弹窗](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md)
11
12
13## 自定义弹窗中的变量如何传递给页面(API 9)
14
15**问题现象**
16
17在自定义弹窗内定义的变量内容,在关闭弹窗或变量变化时需要及时传递给页面,可以通过何种方式传递?
18
19**解决措施**
20
21- 方式一:使用组件的状态变量传递。
22
23- 方式二:在初始化弹窗时,传递一个方法给自定义弹窗,在自定义弹窗中触发该方法,弹窗中变量作为方法的参数。
24
25- 方式三:使用AppStorage或LocalStorage方式管理页面状态,实现自定义弹窗和页面之间状态的共享。
26
27**代码示例**
28
29- 方式一:
30
31  ```
32  @CustomDialog
33  struct CustomDialog01 {
34    @Link inputValue: string
35    controller: CustomDialogController
36    build() {
37      Column() {
38        Text('Change text').fontSize(20).margin({ top: 10, bottom: 10 })
39        TextInput({ placeholder: '', text: this.inputValue }).height(60).width('90%')
40          .onChange((value: string) => {
41            this.inputValue = value
42          })
43      }
44    }
45  }
46
47  @Entry
48  @Component
49  struct DialogDemo01 {
50    @State inputValue: string = 'click me'
51    dialogController: CustomDialogController = new CustomDialogController({
52      builder: CustomDialog01({
53        inputValue: $inputValue
54      })
55    })
56
57    build() {
58      Column() {
59        Button(this.inputValue)
60          .onClick(() => {
61            this.dialogController.open()
62          }).backgroundColor(0x317aff)
63      }.width('100%').margin({ top: 5 })
64    }
65  }
66  ```
67
68- 方式二:
69
70  ```
71  @CustomDialog
72  struct CustomDialog02 {
73    private inputValue: string
74    changeInputValue: (val: string) => void
75    controller: CustomDialogController
76    build() {
77      Column() {
78        Text('Change text').fontSize(20).margin({ top: 10, bottom: 10 })
79        TextInput({ placeholder: '', text: this.inputValue }).height(60).width('90%')
80          .onChange((value: string) => {
81            this.changeInputValue(value)
82          })
83      }
84    }
85  }
86
87  @Entry
88  @Component
89  struct DialogDemo02 {
90    @State inputValue: string = 'click me'
91    dialogController: CustomDialogController = new CustomDialogController({
92      builder: CustomDialog02({
93        inputValue: this.inputValue,
94        changeInputValue: (val: string) => {
95          this.inputValue = val
96        }
97      })
98    })
99
100    build() {
101      Column() {
102        Button(this.inputValue)
103          .onClick(() => {
104            this.dialogController.open()
105          }).backgroundColor(0x317aff)
106      }.width('100%').margin({ top: 5 })
107    }
108  }
109  ```
110
111- 方式三:
112
113  ```
114  let storage = LocalStorage.GetShared()
115  @CustomDialog
116  struct CustomDialog03 {
117    @LocalStorageLink('inputVal')  inputValue: string = ''
118    controller: CustomDialogController
119    build() {
120      Column() {
121        Text('Change text').fontSize(20).margin({ top: 10, bottom: 10 })
122        TextInput({ placeholder: '', text: this.inputValue }).height(60).width('90%')
123          .onChange((value: string) => {
124            this.inputValue = value;
125          })
126      }
127    }
128  }
129
130  @Entry(storage)
131  @Component
132  struct DialogDemo03 {
133    @LocalStorageLink('inputVal') inputValue: string = ''
134    dialogController: CustomDialogController = new CustomDialogController({
135      builder: CustomDialog03()
136    })
137
138    build() {
139      Column() {
140        Button(this.inputValue)
141          .onClick(() => {
142            this.dialogController.open()
143          }).backgroundColor(0x317aff)
144      }.width('100%').margin({ top: 5 })
145    }
146  }
147  ```
148
149
150## 如何获取组件的宽高(API 9)
151
152**问题现象**
153
154组件的宽高信息用于计算布局区域大小以及偏移量等内容,如何获取宽高信息?
155
156**解决措施**
157
158- 方式一:使用组件区域变化事件onAreaChange,在组件初始化或组件尺寸发生变化时触发。
159
160- 方式二:在点击或触摸事件中,事件的回调信息中存在目标元素的区域信息。
161
162**参考链接**
163
164[组件区域变化事件](../reference/apis-arkui/arkui-ts/ts-universal-component-area-change-event.md),[点击事件](../reference/apis-arkui/arkui-ts/ts-universal-events-click.md),[触摸事件](../reference/apis-arkui/arkui-ts/ts-universal-events-touch.md)
165
166
167## 如何一键清空TextInput、TextArea组件内容(API 9)
168
169**问题现象**
170
171TextInput,TextArea组件输入多字符后,需要实现点击清空。
172
173**解决措施**
174
175将状态变量赋值给TextInput或TextArea组件的text属性,在做点击清空事件时为状态变量赋值空字符串。
176
177**代码示例**
178
179```
180struct Index {
181@State text: string = 'Hello World'
182controller: TextInputController = new TextInputController()
183  build() {
184    Row() {
185      Column() {
186        TextInput({ placeholder: 'Please input your words.', text: this.text,
187          controller:this.controller}).onChange((value) => {
188            this.text = value
189          })
190        Button("Clear TextInput").onClick(() => {
191          this.text = "";
192        })
193      }
194      .width('100%')
195    }
196    .height('100%')
197  }
198}
199```
200
201
202## 如何设置自定义弹窗位置(API 9)
203
204**问题现象**
205
206自定义弹窗当前默认在窗口居中显示,当自定义弹窗需要与窗口边框对齐是需要设置自定义弹窗的对齐方式。
207
208**解决措施**
209
210初始化自定义弹窗时,通过alignment参数设置对齐方式,通过offset设置弹窗偏移量。
211
212**参考链接**
213
214[自定义弹窗](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md)
215
216
217## 如何隐藏容器组件的溢出内容(API 9)
218
219**问题现象**
220
221当容器组件内容溢出时,表现为子组件边缘超出容器组件,需要进行隐藏设置。
222
223**解决措施**
224
225将通用属性-形状裁剪clip属性设置为true,表示按照容器边缘轮廓进行裁剪。此属性默认为false,表示不进行裁剪隐藏。
226
227**参考链接**
228
229[形状裁剪](../reference/apis-arkui/arkui-ts/ts-universal-attributes-sharp-clipping.md)
230
231
232## 自定义弹窗大小如何自适应内容(API 9)
233
234**问题现象**
235
236当自定义弹窗中存在可变化区域大小的子组件时,弹窗大小需要跟随自适应。
237
238**解决措施**
239
240- 方式一:采用弹窗容器默认样式。在默认样式中,弹窗容器高度自适应子节点,最大可为窗口高度的90%;弹窗容器的宽度根据栅格系统自适应,不跟随子节点变化。
241
242- 方式二:当显示设置customStyle为true时,弹窗宽高跟随子节点内容适应。
243
244**参考链接**
245
246[自定义弹窗](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md)
247
248
249## 如何理解自定义弹窗中的gridCount参数(API 9)
250
251gridCount参数是指弹窗宽度占栅格列数的个数。系统把窗口宽等分,等分的份数即为栅格列数,不同设备栅格列数不同。假设设备屏幕密度值在320vp<=水平宽度<600vp,所以栅格列数是4,则gridCount的有效值在[1, 4]。
252
253注意:仅采用弹窗默认样式时设置有效。
254
255**参考链接**
256
257[自定义弹窗](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md)
258
259
260## 如何去除自定义弹窗的白色背景(API 9)
261
262**问题现象**
263
264使用自定义弹窗时,默认样式中存在白色背景。
265
266**解决措施**
267
268需要采用自定义样式来消除自定义弹窗的白色背景:
269
2701. 在初始化自定义弹窗时设置customStyle为true。
271
2722. 在定义弹窗时设置组件背景色backgroundColor。
273
274**参考链接**
275
276[自定义弹窗](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md)
277
278
279## TextInput组件密码模式下,右边的眼睛图标能否支持自定义(API 9)
280
281**问题现象**
282
283TextInput组件设置type为InputType.Password时,右侧出现眼睛图标,不能修改图标样式。
284
285**解决措施**
286
287当前图标不支持自定义,可使用TextInput的showPasswordIcon属性隐藏图标,使用Image组件替代控制TextInput组件的type。
288
289**参考链接**
290
291[TextInput组件](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md)
292
293
294## TextInput的onSubmit事件如何使用(API 9)
295
296**问题现象**
297
298TextInput的onSubmit事件怎么触发,以及事件回调的参数类型代表的含义。
299
300**解决措施**
301
302onSubmit事件在外接键盘或软键盘回车时触发该回调,回调的参数为当前软键盘回车键类型。通过TextInput的enterKeyType属性可以设置输入法回车键类型,软键盘回车键样式需要输入法的支持。
303
304**参考链接**
305
306[TextInput组件](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md)
307
308
309## TextInput在聚焦时如何使光标回到起点(API 9)
310
311**问题现象**
312
313TextInput组件在聚焦时,光标位置会自动根据触摸点位置变化,如何使得聚焦时光标固定显示在起点位置?
314
315**解决措施**
316
3171. TextInput组件绑定onEditChange事件,该事件TextInput可进行输入时触发。
318
3192. 在事件回调用TextInputController.caretPosition方法设置光标位置,不过需要用到setTimeout延迟方法。
320
321**代码示例**
322
323```
324@Entry
325@Component
326struct TextInputDemo {
327  controller: TextInputController = new TextInputController()
328
329  build() {
330    Column() {
331      TextInput({ controller: this.controller })
332        .onEditChange((isEditing: boolean) => {
333          if (isEditing) {
334            setTimeout(() => {
335              this.controller.caretPosition(0)
336            }, 100)
337          }
338        })
339    }
340  }
341}
342```
343
344**参考链接**
345
346[TextInput组件](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md)
347
348
349## 如何获取可滚动组件的当前滚动偏移量(API 9)
350
351**问题现象**
352
353可滚动组件包含List,Grid,Scroll等,在发生滚动时如何获取滚动偏移量?
354
355**解决措施**
356
3571. 可滚动组件在初始化时可设置scroller参数,绑定滚动控制器。
358
3592. 通过控制器的currentOffset方法可获取水平和竖直方向的滚动偏移量。
360
361**参考链接**
362
363[Scroll](../reference/apis-arkui/arkui-ts/ts-container-scroll.md#currentoffset)
364
365
366## 如何实现文本竖向排列(API 9)
367
368**问题现象**
369
370使用Text组件时,无法将文本排列方向设置为竖向排列。
371
372**解决措施**
373
374Text组件当前文本排列方向固定为横向排列,要设置为竖向排列,可将文件拆分,使用Flex容器组件装填,设置主轴方向为竖向。
375
376**代码示例**
377
378```
379@Entry
380@Component
381struct Index15 {
382  private message: string = '本文档适用于应用开发的初学者。通过构建一个简单的具有页面跳转/返回功能的应用,快速了解工程目录的主要文件,熟悉应用开发流程。';
383  build() {
384    Flex({ direction: FlexDirection.Column, wrap: FlexWrap.Wrap }) {
385      ForEach(this.message.split(''), (item, index) => {
386        Text(item)
387          .fontSize(30)
388          .flexShrink(0)
389      })
390    }
391  }
392}
393```
394
395
396## 如何将Ability的UI界面设置成透明(API 9)
397
398**问题现象**
399
400如何设置Ability的UI界面为透明
401
402**解决措施**
403
404将最上层容器组件背景色设置为透明,然后通过设置XComponent组件的opacity属性值为0.01来实现。
405
406示例:
407
408```
409build() {
410  Stack() {
411    XComponent({
412    id: 'componentId',
413    type: 'surface',
414    })
415    .width('100%')
416    .height('100%')
417    .opacity(0.01)
418    // 页面内容
419  }
420  .width('100%')
421  .height('100%')
422  .backgroundColor('rgba(255,255,255, 0)')
423}
424```
425
426
427## constraintSize尺寸设置不生效(API 9)
428
429适用于Stage模型。
430
431**问题现象**
432
433constraintSize约束组件尺寸时,子组件内设置百分比宽度,例如width('100%')会采用constraintSize约束中的最大宽乘百分比,导致撑开组件,看起来constraintSize设置没生效。
434
435**解决措施**
436
437可以在外层使用Scroll组件,设置constraintSize,当子组件占用空间超过设置的约束值时,会显示滚动条。
438
439
440## 如何将背景颜色设置为透明(API 9)
441
442**解决措施**
443
444将backgroundColor设置为 '\#00000000'。
445
446
447## Scroll组件滚动到达不了最底部(API 9)
448
449适用于Stage模型。
450
451**问题现象**
452
453Scroll组件在未设置高度情况下,默认为窗口高度,当滚动区域外存在其他组件时,滚动底部区域会出现遮挡。
454
455**解决措施**
456
457Scroll组件需要设置Scroll高度,或者使用Flex布局限制Scroll高度。
458
459
460## 如何自定义Video组件控制栏样式(API 9)
461
462适用于Stage模型。
463
464**解决措施**
465
4661. 通过设置属性controls为false关闭默认控制栏。
467
4682. 设置Video组件的controller。
469
4703. 通过ArkTS实现自定义的控制栏,并通过VideoController控制视频播放。
471
472**代码示例**
473
474```
475// xxx.ets
476@Entry@Componentstruct VideoCreateComponent {
477  @State videoSrc: Resource = $rawfile('video1.mp4')
478  @State previewUri: Resource = $r('app.media.poster1')
479  @State curRate: PlaybackSpeed = PlaybackSpeed.Speed_Forward_1_00_X
480  @State isAutoPlay: boolean = false
481  @State showControls: boolean = true
482  controller: VideoController = new VideoController()
483   build() {
484    Column() {
485      Video({
486        src: this.videoSrc,
487        previewUri: this.previewUri,
488        currentProgressRate: this.curRate,
489        controller: this.controller
490      }).width('100%').height(600)
491        .autoPlay(this.isAutoPlay)
492        .controls(this.showControls)
493        .onStart(() => {
494          console.info('onStart')
495        })
496        .onPause(() => {
497          console.info('onPause')
498        })
499        .onFinish(() => {
500          console.info('onFinish')
501        })
502        .onError(() => {
503          console.info('onError')
504        })
505        .onPrepared((e) => {
506          console.info('onPrepared is ' + e.duration)
507        })
508        .onSeeking((e) => {
509          console.info('onSeeking is ' + e.time)
510        })
511        .onSeeked((e) => {
512          console.info('onSeeked is ' + e.time)
513        })
514        .onUpdate((e) => {
515          console.info('onUpdate is ' + e.time)
516        })
517             Row() {
518        Button('src').onClick(() => {
519          this.videoSrc = $rawfile('video2.mp4') // 切换视频源
520        }).margin(5)
521        Button('previewUri').onClick(() => {
522          this.previewUri = $r('app.media.poster2') // 切换视频预览海报
523        }).margin(5)
524
525        Button('controls').onClick(() => {
526          this.showControls = !this.showControls // 切换是否显示视频控制栏
527        }).margin(5)
528      }
529       Row() {
530        Button('start').onClick(() => {
531          this.controller.start() // 开始播放
532        }).margin(5)
533        Button('pause').onClick(() => {
534          this.controller.pause() // 暂停播放
535        }).margin(5)
536        Button('stop').onClick(() => {
537          this.controller.stop() // 结束播放
538        }).margin(5)
539        Button('setTime').onClick(() => {
540          this.controller.setCurrentTime(10, SeekMode.Accurate) // 精准跳转到视频的10s位置
541        }).margin(5)
542      }
543       Row() {
544        Button('rate 0.75').onClick(() => {
545          this.curRate = PlaybackSpeed.Speed_Forward_0_75_X // 0.75倍速播放
546        }).margin(5)
547        Button('rate 1').onClick(() => {
548          this.curRate = PlaybackSpeed.Speed_Forward_1_00_X // 原倍速播放
549        }).margin(5)
550        Button('rate 2').onClick(() => {
551          this.curRate = PlaybackSpeed.Speed_Forward_2_00_X // 2倍速播放
552        }).margin(5)
553      }
554    }
555  }}
556```
557
558**参考链接**
559
560[Video](../reference/apis-arkui/arkui-ts/ts-media-components-video.md#start)
561
562## 如何设置组件不同状态下的样式(API 9)
563
564**问题现象**
565
566对应组件的不同状态(如无状态、按下、禁用、聚焦、点击),显示不同的样式。
567
568**解决措施**
569
570使用多态样式,在组件的StateStyles接口中,定义组件不同状态下的样式。
571
572**代码示例**
573
574```
575//xxx.ts
576@Entry
577@Component
578struct StyleExample {
579  @State isEnable: boolean = true;
580
581  @Styles pressedStyles() {
582    .backgroundColor("#ED6F21")
583    .borderRadius(10)
584    .borderStyle(BorderStyle.Dashed)
585    .borderWidth(2)
586    .borderColor('#33000000')
587    .width(120)
588    .height(30)
589    .opacity(1)
590  }
591  build() {
592    Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center}) {
593      Text("pressed")
594        .backgroundColor('#0A59F7')
595        .borderRadius(20)
596        .borderStyle(BorderStyle.Dotted)
597        .borderWidth(2)
598        .borderColor(Color.Red)
599        .width(100)
600        .height(25)
601        .opacity(1)
602        .fontSize(14)
603        .fontColor(Color.White)
604        .stateStyles({
605          pressed: this.pressedStyles
606        })
607        .margin({
608          bottom: 20
609        })
610        .textAlign(TextAlign.Center)
611    }
612    .width(350)
613    .height(300)
614  }
615}
616```
617
618**参考链接**
619
620[多态样式](../reference/apis-arkui/arkui-ts/ts-universal-attributes-polymorphic-style.md)
621
622## Scroll内Flex加宽高与滑动冲突(API 9)
623
624适用于Stage模型。
625
626**问题现象**
627
628当在Scroll组件中添加容器组件,并设置该容器组件的尺寸时,会破坏滚动布局。
629
630**解决措施**
631
632Scroll组件中的容器组件不设置尺寸,大小由内容撑开。
633
634
635## 父组件中如何处理子组件内点击事件(API 9)
636
637适用于Stage模型。
638
639在父组件中初始化子组件时,将父组件中定义的方法,传递给子组件,在子组件中调用该方法,类似于变量传递。
640
641**代码示例**
642
643```
644class Model {
645  value: string
646}
647@Entry
648@Component
649struct EntryComponent {
650  test() {
651    console.log('testTag test in my component');
652  }
653  build() {
654    Column() {
655      MyComponent({ title: { value: 'Hello World 2' }, count: 7, onClick: this.test }) //初始化时传递定义的方法
656    }
657  }
658}
659
660@Component
661struct MyComponent {
662  @State title: Model = { value: 'Hello World' }
663  @State count: number = 0
664  onClick: any;
665  private toggle: string = 'Hello World'
666  private increaseBy: number = 1
667
668  build() {
669    Column() {
670      Text(`${this.title.value}`).fontSize(30)
671      Button(`Click to increase count=${this.count}`)
672        .margin(20)
673        .onClick(() => {
674          // 修改内部状态变量count
675          this.count += this.increaseBy
676          this.onClick.call();
677        })
678    }
679  }
680}
681```
682
683
684## 如何主动拉起软键盘(API 9)
685
686**解决措施**
687
688可以通过focusControl.requestFocus控制输入框获焦,组件获焦后会自动弹起软键盘
689
690**参考链接**
691
692焦点控制:[焦点控制](../reference/apis-arkui/arkui-ts/ts-universal-attributes-focus.md)
693
694
695## SideBarContainer如何设置controlButton属性(API 9)
696
697**解决措施**
698
699示例代码:
700
701```
702@Entry
703@Component
704struct SideBarContainerExample {
705  normalIcon : Resource = $r("app.media.icon")
706  selectedIcon: Resource = $r("app.media.icon")
707  @State arr: number[] = [1, 2, 3]
708  @State current: number = 1
709
710  build() {
711    SideBarContainer(SideBarContainerType.Embed)
712    {
713      Column() {
714        ForEach(this.arr, (item, index) => {
715          Column({ space: 5 }) {
716            Image(this.current === item ? this.selectedIcon : this.normalIcon).width(64).height(64)
717            Text("Index0" + item)
718              .fontSize(25)
719              .fontColor(this.current === item ? '#0A59F7' : '#999')
720              .fontFamily('source-sans-pro,cursive,sans-serif')
721          }
722          .onClick(() => {
723            this.current = item
724          })
725        }, item => item)
726      }.width('100%')
727      .justifyContent(FlexAlign.SpaceEvenly)
728      .backgroundColor('#19000000')
729
730
731      Column() {
732        Text('SideBarContainer content text1').fontSize(25)
733        Text('SideBarContainer content text2').fontSize(25)
734      }
735      .margin({ top: 50, left: 20, right: 30 })
736    }
737    .sideBarWidth(150)
738    .minSideBarWidth(50)
739    .controlButton({left:32,
740      top:32,
741      width:32,
742      height:32,
743      icons:{shown: $r("app.media.icon"),
744        hidden: $r("app.media.icon"),
745        switching: $r("app.media.icon")}})
746    .maxSideBarWidth(300)
747    .onChange((value: boolean) => {
748      console.info('status:' + value)
749    })
750  }
751}
752```
753
754## 如何实现主动控制组件刷新(API 10)
755
756**解决措施**
757
758Canvas组件最终的显示内容分两种,一种是组件通用属性的绘制内容,比如背景色,boarder等这类组件属性方法设置的渲染属性,这类属性是可以通过状态变量驱动更新的。
759另一种是通过CanvasRenderingContext2D绘制接口由应用自行绘制的内容。该类命令时绘制接口不响应状态变量,该类接口内置表脏功能,只要调用就会在下一帧刷新绘制内容,不需要开发者显式刷新。
760
761**参考链接**
762
763[CanvasRenderingContext2D](../reference/apis-arkui/arkui-ts/ts-canvasrenderingcontext2d.md)
764
765## 怎么解决列表组件List在不设置高度的情况下,会出现滑动不到底的问题(API 10)
766
767**原因分析**
768
769List没有设置高度时,如果子组件总高度大于List父组件的高度时,List会取List父组件高度。如果List有其他兄弟节点,可能会吧List部分顶出父组件显示区域外,看起来像是划不到底部。
770
771**解决措施**
772
773List组件设置layoutWeight(1)属性,将剩余空间全部分配给List组件。
774
775**参考链接**
776
777[尺寸设置](../reference/apis-arkui/arkui-ts/ts-universal-attributes-size.md)
778
779## 如何实现瀑布流滑动时,数据的无限加载和显示(API 10)
780
781**解决措施**
782
7831.使用LazyForEach做瀑布流子节点。
784
7852.参考WaterFlow高性能开发指导在FlowItem的onAppear中判断是否即将触底,提前在LazyForEach数据源尾部新增数据;或在onScrollIndex11+事件中根据当前index进行判断。
786
787**参考链接**
788
789[WaterFlow高性能开发指导](../performance/waterflow_optimization.md)
790
791## customDialog中调用router.push启动新页面,会把customDialog关闭,怎么实现在不关闭弹窗的前提下启动新页面(API 10)
792
793**解决措施**
794
795开发者在路由跳转时,需要获取到主窗口的uiContext,再调用路由跳转。
796
797**参考链接**
798
799[自定义弹窗](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md)
800
801## 当前ArkUI-X的支持进展如何,有无明确路线图(API 10)
802
803**解决措施**
804
8051.进展:ArkUI-X当前已经开源,首版本已于2023-12-15正式发布,当前支持Android、iOS跨平台;另外,也在探索和试验桌面平台与Web平台的支持。
806
8072.[路线图](https://gitee.com/arkui-x/docs/blob/master/zh-cn/roadmap/ArkUI-X-roadmap-2023.md)808
809**参考链接**
810
811[ArkUI-X](https://gitee.com/arkui-x)
812
813## 应用如何在自定义组件的构建流程里跟踪组件数据或者状态(API 10)
814
815**问题现象**
816
817UI的构建build方法内无法插入日志,导致应用无法感知UI绘制流程,不利于调试UI,定位UI问题。
818
819**解决措施**
820
821使用@Watch回调来监测状态变量的变化,如果执行回调函数,说明在下一次vysnc信号发送时,使用该状态变量的UI会刷新绘制。
822
823示例代码如下:
824
825```ts
826@Prop @Watch('onCountUpdated') count: number = 0;
827@State total: number = 0;
828// @Watch 回调
829onCountUpdated(propName: string): void {
830  this.total += this.count;
831}
832```
833
834**参考链接**
835
836[@Watch装饰器:状态变量更改通知](../quick-start/arkts-watch.md)
837
838## 自定义component不支持继承语法,针对其他框架支持的自定义组件继承及封装能力,ArkUI的解决方案是什么(API 10)
839
840**解决措施**
841
842对于声明式的自定义组件场景,不会提供继承的能力,需要使用组合的方式进行扩展,并结合后续提供的Modifier机制进行对现有组件属性的继承、复用和传递。
843
844## 组件支持的参数类型及参数单位类型区别是什么,使用场景是什么(API 10)
845
846**解决措施**
847
848屏幕像素单位px(pixel),表示屏幕上的实际像素,1px代表设备屏幕上的一个像素点。视窗逻辑像素单位lpx,lpx单位为实际屏幕宽度与逻辑宽度(通过designWidth配置)的比值,标识页面设计基准宽度。以此为基准,根据实际设备宽度来缩放元素大小。距离使用vp(virtual pixel),字体大小使用fp(font pixel),虚拟像素单位vp(virtual pixel),vp具体计算公式为:vp= px/(DPI/160)。
849以屏幕相对像素为单位, 是一台设备针对应用而言所具有的虚拟尺寸(区别于屏幕硬件本身的像素单位)。它提供了一种灵活的方式来适应不同屏幕密度的显示效果,使用虚拟像素,使元素在不同密度的设备上具有一致的视觉体量。字体像素单位fp(font pixel),字体像素(font pixel)大小默认情况下与vp相同,即默认情况下1fp=1vp。如果用户在设置中选择了更大的字体,字体的实际显示大小就会在vp的基础上乘以scale系数,即1fp=1vp*scale。Percentage - 需要指定以%像素单位,如'10%'。
850Resource - 资源引用类型,引入系统资源或者应用资源中的尺寸。
851