1# ArkUI子系统Changelog
2
3## cl.arkui.1 @ComponentV2自定义组件冻结变更
4
5**访问级别**
6
7公开接口
8
9**变更原因**
10
11当@ComponentV2装饰的子组件设置freezeWhenInactive为true时,父组件没有设置,则子组件的组件冻结功能不生效。
12
13为了确保组件冻结功能生效,需要修改当子组件设置freezeWhenInactive为true,无论父组件是否设置,子组件的组件冻结功能应生效。
14
15**变更影响**
16
17该变更为不兼容变更。
18
19变更前:仅子组件开启了组件冻结,父组件没有开启组件冻结,不会对子组件开启冻结功能。
20
21变更后:仅子组件开启了组件冻结,父组件没有开启组件冻结,子组件会启用组件冻结功能。
22
23**起始API Level**
24
25API 12
26
27**变更发生版本**
28
29从OpenHarmony SDK 5.0.0.56开始。
30
31**变更的接口/组件**
32
33@ComponentV2的freezeWhenInactive接口。
34
35**适配指导**
36
37当子组件使用了组件冻结,父组件没有使用组件冻结的情况下,当组件处于inactive时,子组件组件冻结功能生效。示例如下:
38
39页面1:
40
41```ts
42// Page1.ets
43import { router } from '@kit.ArkUI';
44
45@ObservedV2
46export class Book {
47  @Trace name: string = "100";
48
49  constructor(page: string) {
50    this.name = page;
51  }
52}
53
54@Entry
55@ComponentV2
56export struct Page1 {
57  build() {
58    Column() {
59      Child()
60    }
61  }
62}
63
64@ComponentV2({ freezeWhenInactive: true })
65export struct Child {
66  @Local bookTest: Book = new Book("A Midsummer Night’s Dream");
67
68  @Monitor("bookTest.name")
69  onMessageChange(monitor: IMonitor) {
70    console.log(`The book name change from ${monitor.value()?.before} to ${monitor.value()?.now}`);
71  }
72
73  textUpdate(): number{
74    console.log("The text is update");
75    return 25;
76  }
77
78  build() {
79    Column() {
80      Text(`The book name is  ${this.bookTest.name}`).fontSize(this.textUpdate())
81      Button('go to next page').fontSize(30)
82        .onClick(() => {
83          router.pushUrl({ url: 'pages/Page2' });
84          setTimeout(() => {
85            this.bookTest = new Book("Jane Austen oPride and Prejudice");
86          }, 1000);
87        })
88    }
89  }
90}
91```
92
93页面2:
94
95```ts
96// Page2.ets
97import { router } from '@kit.ArkUI';
98
99@Entry
100@ComponentV2
101struct Page2 {
102  build() {
103    Column() {
104      Text(`This is the page`).fontSize(50)
105      Button('Back')
106        .onClick(() => {
107          router.back();
108        })
109    }
110  }
111}
112```
113
114如果开发者不关注组件冻结的功能是否生效,只是调用了其接口,会发现组件冻结能力在该场景下并没有生效,即在跳转到页面2后,改变状态变量`@Local bookTest`,页面1的Child组件还会刷新,其@Monitor也会调用。
115
116trace如下:
117![Example Image](../../figures/freeze2.png)
118
119变更后,修复了上面示例中组件冻结接口不生效的行为,变更后的行为是:
120- 页面1的子组件Child,设置`freezeWhenInactive: true`, 开启了组件冻结功能。
121- 点击Button跳转到页面2,然后延迟1s更新状态变量`bookTest`。在更新`bookTest`的时候,已经跳转到页面2,页面1的组件处于inactive状态,又因为Child组件开启了组件冻结,状态变量`@Local bookTest`将不响应更新,其@Monitor不会调用,状态变量关联的节点不会刷新。
122
123变更后trace如下:
124![Example Image](../../figures/freeze1.png)
125
126如果开发者希望Page1在不可见的时候依旧刷新,和正常触发@Monitor回调,建议不使用组件冻结功能,即不设置`freezeWhenInactive: true`。示例如下:
127
128
129页面1:
130
131```ts
132// Page1.ets
133import { router } from '@kit.ArkUI';
134
135@ObservedV2
136export class Book {
137  @Trace name: string = "100";
138
139  constructor(page: string) {
140    this.name = page;
141  }
142}
143
144@Entry
145@ComponentV2
146export struct Page1 {
147  build() {
148    Column() {
149      Child()
150    }
151  }
152}
153
154@ComponentV2
155export struct Child {
156  @Local bookTest: Book = new Book("A Midsummer Night’s Dream");
157
158  @Monitor("bookTest.name")
159  onMessageChange(monitor: IMonitor) {
160    console.log(`The book name change from ${monitor.value()?.before} to ${monitor.value()?.now}`);
161  }
162
163  textUpdate(): number{
164    console.log("The text is update");
165    return 25;
166  }
167
168  build() {
169    Column() {
170      Text(`The book name is  ${this.bookTest.name}`).fontSize(this.textUpdate())
171      Button('go to next page').fontSize(30)
172        .onClick(() => {
173          router.pushUrl({ url: 'pages/Page2' });
174          setTimeout(() => {
175            this.bookTest = new Book("Jane Austen oPride and Prejudice");
176          }, 1000);
177        })
178    }
179  }
180}
181```
182
183页面2:
184
185```ts
186// Page2.ets
187import { router } from '@kit.ArkUI';
188
189@Entry
190@ComponentV2
191struct Page2 {
192  build() {
193    Column() {
194      Text(`This is the page`).fontSize(50)
195      Button('Back')
196        .onClick(() => {
197          router.back();
198        })
199    }
200  }
201}
202```
203
204当子组件Child不使用组件冻结功能时,跳转到页面2,修改状态变量将响应更新,@Monitor被调用,状态变量关联的节点将会刷新。
205
206
207## cl.arkui.2 当AttributeModifer的applyNormalAttribute方法中instance参数设置为资源类型数据时更新的行为发生变更
208
209**访问级别**
210
211公开接口
212
213**变更原因**
214
215当开发者使用资源文件作为AttributeModifer的applyNormalAttribute方法中instance对象的入参时,无法通过配置资源文件更新参数,该行为与系统资源的规格不一致。
216
217**变更影响**
218
219该变更为不兼容变更。
220
221运行以下示例时:
222
223```ts
224class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
225  private color?: ResourceColor;
226  private fontColor?: ResourceColor;
227
228  constructor(color: ResourceColor, fontColor: ResourceColor) {
229    this.color = color;
230    this.fontColor = fontColor;
231  }
232
233  applyNormalAttribute(instance: ButtonAttribute): void {
234    // instance为Button的属性对象,设置正常状态下属性值
235    instance.backgroundColor(this.color)
236      .fontColor(this.fontColor)
237      .borderWidth(1)
238  }
239}
240
241@Entry
242@Component
243struct attributeDemo {
244  @State modifier: MyButtonModifier = new MyButtonModifier($r('app.color.backColor'), $r('app.color.fontColor'));
245
246  build() {
247    Row() {
248      Column() {
249        Button("Button")
250          .attributeModifier(this.modifier)
251      }.width("100%")
252    }
253    .height('100%')
254    .backgroundColor(Color.White)
255  }
256}
257```
258
259```json
260// src/main/resources/base/element/color.json
261{
262  "color": [
263    {
264      "name": "start_window_background",
265      "value": "#FFFFFF"
266    },
267    {
268      "name": "backColor",
269      "value": "#000000"
270    },
271    {
272      "name": "fontColor",
273      "value": "#FFFFFF"
274    }
275  ]
276}
277```
278
279```json
280// src/main/resources/dark/element/color.json
281{
282  "color": [
283    {
284      "name": "start_window_background",
285      "value": "#000000"
286    },
287    {
288      "name": "backColor",
289      "value": "#FFFFFF"
290    },
291    {
292      "name": "fontColor",
293      "value": "#000000"
294    }
295  ]
296}
297```
298
299| 变更前                                                                               | 变更后                                                                             |
300| ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
301| 浅色模式拉起。<br>![light_mode](figures/light_mode1.jpg)                             | 浅色模式拉起。<br>![light_mode](figures/light_mode1.jpg)                           |
302|                                                                                      |
303| 切换深色时,无法使用资源文件触发UI的更新。<br>![light_mode](figures/light_mode1.jpg) | 切换深色时,可以使用资源文件触发UI的更新。<br>![dark_mode](figures/dark_mode1.jpg) |
304|                                                                                      |
305
306**起始API Level**
307
308API 11
309
310**变更发生版本**
311
312从OpenHarmony SDK 5.0.0.56开始。
313
314**变更的接口/组件**
315
316common.d.ts文件attributeModifier接口。
317
318**适配指导**
319
320默认行为变更,无需适配,但应注意变更后的行为是否对整体应用逻辑产生影响。
321
322如不期望资源随配置文件更新可以将资源取出后使用。
323
324```ts
325class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
326  public  color?: ResourceColor;
327  public fontColor?: ResourceColor;
328
329  constructor(color: ResourceColor, fontColor: ResourceColor) {
330    this.color = color;
331    this.fontColor = fontColor;
332  }
333
334  applyNormalAttribute(instance: ButtonAttribute): void {
335    // instance为Button的属性对象,设置正常状态下属性值
336    instance.backgroundColor(this.color)
337      .fontColor(this.fontColor)
338      .borderWidth(1)
339  }
340}
341
342@Entry
343@Component
344struct attributeDemo {
345  @State modifier: MyButtonModifier = new MyButtonModifier($r('app.color.backColor'), $r('app.color.fontColor'));
346
347  aboutToAppear(): void {
348    // 解析获取资源文件。
349    this.modifier.color = getContext().resourceManager.getColorSync($r('app.color.backColor').id);
350    this.modifier.fontColor = getContext().resourceManager.getColorSync($r('app.color.fontColor').id);
351  }
352
353  build() {
354    Row() {
355      Column() {
356        Button("Button")
357          .attributeModifier(this.modifier)
358      }.width("100%")
359    }
360    .height('100%')
361    .backgroundColor(Color.White)
362  }
363}
364```
365
366| 变更前                                                   | 变更后                                                 |
367| -------------------------------------------------------- | ------------------------------------------------------ |
368| 浅色模式拉起。<br>![light_mode](figures/light_mode1.jpg) | 深色模式拉起。<br>![dark_mode](figures/dark_mode1.jpg) |
369| 切换深色。<br>![light_mode](figures/light_mode1.jpg)     | 切换浅色。<br>![dark_mode](figures/dark_mode1.jpg)     |
370
371## cl.arkui.3 废弃gridSpan和gridOffset属性
372**访问级别**
373
374公开接口
375
376**废弃原因**
377
378gridSpan和gridOffset属性仅设置在gridContaier的子组件上有效,gridContainer组件已废弃。
379
380**废弃影响**
381
382该变更为接口废弃,开发者需使用替代接口。
383
384**废弃发生版本**
385
386从OpenHarmony SDK 5.0.0.56开始。
387
388**废弃的接口/组件**
389
390|           废弃接口            |                  替代接口                  |
391| :---------------------------: | :----------------------------------------: |
392|  gridSpan(value: number): T;  |  GridCol(option?: GridColOptions)中的span  |
393| gridOffset(value: number): T; | GridCol(option?: GridColOptions)中的offset |
394
395**适配指导**
396
397废弃前使用gridSpan、gridOffset属性的栅格。
398
399```ts
400// xxx.ets
401@Entry
402@Component
403struct GridContainerExample1 {
404  build() {
405    Column() {
406      Text('gridSpan,gridOffset').fontSize(15).fontColor(0xCCCCCC).width('90%')
407      GridContainer() {
408        Row() {
409          Row() {
410            Text('Left').fontSize(25)
411          }
412          .gridSpan(1)
413          .height("100%")
414          .backgroundColor(0x66bbb2cb)
415
416          Row() {
417            Text('Center').fontSize(25)
418          }
419          .gridSpan(2)
420          .gridOffset(1)
421          .height("100%")
422          .backgroundColor(0x66b6c5d1)
423
424          Row() {
425            Text('Right').fontSize(25)
426          }
427          .gridSpan(1)
428          .gridOffset(3)
429          .height("100%")
430          .backgroundColor(0x66bbb2cb)
431        }.height(200)
432      }
433    }
434  }
435}
436```
437
438使用GridRow容器,并且子组件为GridCol。GridCol构造中设置span(对应废弃的gridSpan)、offset(对应废弃的gridOffset)属性的栅格。
439```ts
440// xxx.ets
441@Entry
442@Component
443struct GridRowExample {
444  @State bgColors: Color[] = [Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Pink, Color.Grey, Color.Blue, Color.Brown]
445  @State currentBp: string = 'unknown'
446
447  build() {
448    Column() {
449      GridRow({
450        columns: 5,
451        gutter: { x: 5, y: 10 },
452        breakpoints: { value: ["400vp", "600vp", "800vp"],
453          reference: BreakpointsReference.WindowSize },
454        direction: GridRowDirection.Row
455      }) {
456          GridCol({ span: { xs: 1, sm: 2, md: 3, lg: 4 }, offset: 0, order: 0 }) {
457            Text('Left').fontSize(25)
458          }.borderColor(color).borderWidth(2)
459          GridCol({ span: { xs: 1, sm: 2, md: 3, lg: 4 }, offset: 1, order: 0 }) {
460            TText('Center').fontSize(25)
461          }.borderColor(color).borderWidth(2)
462          GridCol({ span: { xs: 1, sm: 2, md: 3, lg: 4 }, offset: 2, order: 0 }) {
463             Text('Right').fontSize(25)
464          }.borderColor(color).borderWidth(2)
465      }.width("100%").height("100%")
466      .onBreakpointChange((breakpoint) => {
467        this.currentBp = breakpoint
468      })
469    }.width('80%').margin({ left: 10, top: 5, bottom: 5 }).height(200)
470    .border({ color: '#880606', width: 2 })
471  }
472}
473```
474
475## cl.arkui.4 Chip与ChipGroup组件布局重构
476
477**访问级别**
478
479公开接口
480
481**变更原因**
482
483原来的布局逻辑未考虑像素取整情况,导致部分界面显示异常。因此发起布局重构,重构后会因为像素取整导致组件的整体宽度可能差1px。
484
485**变更影响**
486
487该变更为不兼容变更。
488
489| 变更前                                                                     | 变更后                                                                 |
490| -------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
491| 组件布局过程中不会进行像素取整 <br>![chip_before](figures/chip_before.PNG) | 组件布局过程中会进行像素取整<br>![chip_before](figures/chip_after.PNG) |
492
493变更后可能影响自动化UI测试结果,产生像素级偏差。
494
495**起始API Level**
496
497API 12
498
499**变更发生版本**
500
501从OpenHarmony SDK 5.0.0.56开始。
502
503**变更的接口/组件**
504
505Chip与ChipGroup组件。
506
507**适配指导**
508
509默认效果变更,无需适配,但应注意变更后的默认效果是否符合开发者预期,如不符合则应自定义修改效果控制变量以达到预期。
510
511