1 # 请求UI绘制帧率
2 
3 如果开发者需要以独立的帧率绘制更新操作UI界面时,可以通过DisplaySync来实现。应用中绘制内容的帧率可以使用DisplaySync实例来控制,具体请查阅[@ohos.graphics.displaySync(可变帧率)](../reference/apis-arkgraphics2d/js-apis-graphics-displaySync.md)。
4 
5 ## 开发步骤
6 
7 此处以不同帧率改变文件组件字体大小为例,来模拟不同UI绘制帧率的效果。
8 
9 1. 导入模块。
10 
11    ```ts
12    import { displaySync } from '@kit.ArkGraphics2D';
13    ```
14 
15 2. 定义和构建DisplaySync对象。
16 
17    ```ts
18    @Entry
19    @Component
20    struct Index {
21      // 定义两个DisplaySync变量,未初始化
22      private backDisplaySyncSlow: displaySync.DisplaySync | undefined = undefined;
23      private backDisplaySyncFast: displaySync.DisplaySync | undefined = undefined;
24    }
25    ```
26 
27 3. 定义两个文本组件。
28 
29    ```ts
30    @State drawFirstSize: number = 25;
31    @State drawSecondSize: number = 25;
32    @Builder doSomeRenderFirst() {
33     Text('30')
34       .fontSize(this.drawFirstSize)
35    }
36 
37    @Builder doSomeRenderSecond() {
38     Text('60')
39       .fontSize(this.drawSecondSize)
40    }
41    ```
42 
43 4. 通过DisplaySync实例设置帧率和注册订阅函数。
44 
45    > **说明:**
46    >
47    > 订阅函数运行于UI主线程,故涉及UI线程的耗时操作不应运行于订阅函数中,以免影响性能。
48 
49    ```ts
50    CreateDisplaySyncSlow() {
51        let range : ExpectedFrameRateRange = { // 创建和配置帧率参数
52          expected: 30, // 设置期望绘制帧率为30hz
53          min: 0, // 配置帧率范围
54          max: 120 // 配置帧率范围
55        };
56 
57        let draw30 = (intervalInfo: displaySync.IntervalInfo) => { // 订阅回调函数,字体大小在25到150之间变化
58          if (this.isBigger_30) {
59            this.drawFirstSize += 1;
60            if (this.drawFirstSize > 150) {
61              this.isBigger_30 = false;
62            }
63          } else {
64            this.drawFirstSize -= 1;
65            if (this.drawFirstSize < 25) {
66              this.isBigger_30 = true;
67            }
68          }
69        };
70 
71        this.backDisplaySyncSlow = displaySync.create(); // 创建DisplaySync实例
72        this.backDisplaySyncSlow.setExpectedFrameRateRange(range); // 设置帧率
73        this.backDisplaySyncSlow.on("frame", draw30); // 订阅frame事件和注册订阅函数
74    }
75    ```
76 
77 5. 开始每帧回调。
78 
79    ```ts
80    Button('Start')
81      .id('CustomDrawStart')
82      .fontSize(14)
83      .fontWeight(500)
84      .margin({ bottom: 10, left: 5 })
85      .fontColor(Color.White)
86      .onClick((): void => {
87          if (this.backDisplaySyncSlow == undefined) {
88            this.CreateDisplaySyncSlow();
89          }
90          if (this.backDisplaySyncFast == undefined) {
91            this.CreateDisplaySyncFast();
92          }
93          if (this.backDisplaySyncSlow) {
94            this.backDisplaySyncSlow.start();
95          }
96          if (this.backDisplaySyncFast) {
97            this.backDisplaySyncFast.start();
98          }
99        })
100        .width('20%')
101        .height(40)
102        .shadow(ShadowStyle.OUTER_DEFAULT_LG)
103    ```
104 
105    > **说明:**
106    >
107    > 创建的DisplaySync实例在start使能后需要aboutToDisappear函数中进行stop操作并置空,避免内存泄漏问题。
108    ```ts
109    aboutToDisappear() {
110      if (this.backDisplaySyncSlow) {
111        this.backDisplaySyncSlow.stop();
112        this.backDisplaySyncSlow = undefined;
113      }
114      if (this.backDisplaySyncFast) {
115        this.backDisplaySyncFast.stop();
116        this.backDisplaySyncFast = undefined;
117      }
118    }
119    ```
120 
121 6. 结束每帧回调。
122 
123    ```ts
124    Button('Stop')
125      .id('CustomDrawStop')
126      .fontSize(14)
127      .fontWeight(500)
128      .margin({ bottom: 10, left: 5 })
129      .fontColor(Color.White)
130      .onClick((): void => {
131        if (this.backDisplaySyncSlow) {
132            this.backDisplaySyncSlow.stop();
133        }
134        if (this.backDisplaySyncFast) {
135            this.backDisplaySyncFast.stop();
136        }
137      })
138      .width('20%')
139      .height(40)
140      .shadow(ShadowStyle.OUTER_DEFAULT_LG)
141    ```
142 
143 ## 完整示例
144 ```ts
145 import { displaySync } from '@kit.ArkGraphics2D';
146 
147 @Entry
148 @Component
149 struct Index {
150   @State drawFirstSize: number = 25;
151   @State drawSecondSize: number = 25;
152   private backDisplaySyncSlow: displaySync.DisplaySync | undefined = undefined;
153   private backDisplaySyncFast: displaySync.DisplaySync | undefined = undefined;
154   private isBigger_30:boolean = true;
155   private isBigger_60:boolean = true;
156 
157   @Builder doSomeRenderFirst() {
158     Text('30')
159       .fontSize(this.drawFirstSize)
160   }
161 
162   @Builder doSomeRenderSecond() {
163     Text('60')
164       .fontSize(this.drawSecondSize)
165   }
166 
167   CreateDisplaySyncSlow() {
168     // 定义期望绘制帧率
169     let range : ExpectedFrameRateRange = {
170       expected: 30,
171       min: 0,
172       max: 120
173     };
174 
175     let draw30 = (intervalInfo: displaySync.IntervalInfo) => {
176       if (this.isBigger_30) {
177         this.drawFirstSize += 1;
178         if (this.drawFirstSize > 150) {
179           this.isBigger_30 = false;
180         }
181       } else {
182         this.drawFirstSize -= 1;
183         if (this.drawFirstSize < 25) {
184           this.isBigger_30 = true;
185         }
186       }
187     };
188 
189     this.backDisplaySyncSlow = displaySync.create(); // 创建DisplaySync实例
190     this.backDisplaySyncSlow.setExpectedFrameRateRange(range); // 设置帧率
191     this.backDisplaySyncSlow.on("frame", draw30); // 订阅frame事件和注册订阅函数
192   }
193 
194   CreateDisplaySyncFast() {
195     // 定义期望绘制帧率
196     let range : ExpectedFrameRateRange = {
197       expected: 60,
198       min: 0,
199       max: 120
200     };
201 
202     let draw60 = (intervalInfo: displaySync.IntervalInfo) => {
203       if (this.isBigger_60) {
204         this.drawSecondSize += 1;
205         if (this.drawSecondSize > 150) {
206           this.isBigger_60 = false;
207         }
208       } else {
209         this.drawSecondSize -= 1;
210         if (this.drawSecondSize < 25) {
211           this.isBigger_60 = true;
212         }
213       }
214 
215     };
216 
217     this.backDisplaySyncFast= displaySync.create(); // 创建DisplaySync实例
218     this.backDisplaySyncFast.setExpectedFrameRateRange(range); // 设置帧率
219     this.backDisplaySyncFast.on("frame", draw60); // 订阅frame事件和注册订阅函数
220   }
221 
222   aboutToDisappear() {
223     if (this.backDisplaySyncSlow) {
224       this.backDisplaySyncSlow.stop(); // DisplaySync失能关闭
225       this.backDisplaySyncSlow = undefined; // 实例置空
226     }
227     if (this.backDisplaySyncFast) {
228       this.backDisplaySyncFast.stop(); // DisplaySync失能关闭
229       this.backDisplaySyncFast = undefined; // 实例置空
230     }
231   }
232 
233   build() {
234     Column() {
235       Row() {
236         this.doSomeRenderFirst();
237       }
238       .height('40%')
239 
240       Row() {
241         this.doSomeRenderSecond();
242       }
243       .height('40%')
244 
245       Row() {
246         Button('Start')
247           .id('CustomDrawStart')
248           .fontSize(14)
249           .fontWeight(500)
250           .margin({ bottom: 10, left: 5 })
251           .fontColor(Color.White)
252           .onClick((): void => {
253             if (this.backDisplaySyncSlow == undefined) {
254               this.CreateDisplaySyncSlow();
255             }
256             if (this.backDisplaySyncFast == undefined) {
257               this.CreateDisplaySyncFast();
258             }
259             if (this.backDisplaySyncSlow) {
260               this.backDisplaySyncSlow.start(); // DisplaySync使能开启
261             }
262             if (this.backDisplaySyncFast) {
263               this.backDisplaySyncFast.start(); // DisplaySync使能开启
264             }
265           })
266           .width('20%')
267           .height(40)
268           .shadow(ShadowStyle.OUTER_DEFAULT_LG)
269 
270         Button('Stop')
271           .id('CustomDrawStop')
272           .fontSize(14)
273           .fontWeight(500)
274           .margin({ bottom: 10, left: 5 })
275           .fontColor(Color.White)
276           .onClick((): void => {
277             if (this.backDisplaySyncSlow) {
278               this.backDisplaySyncSlow.stop(); // DisplaySync失能关闭
279             }
280             if (this.backDisplaySyncFast) {
281               this.backDisplaySyncFast.stop(); // DisplaySync失能关闭
282             }
283           })
284           .width('20%')
285           .height(40)
286           .shadow(ShadowStyle.OUTER_DEFAULT_LG)
287       }
288       .width('100%')
289       .justifyContent(FlexAlign.Center)
290       .shadow(ShadowStyle.OUTER_DEFAULT_SM)
291       .alignItems(VerticalAlign.Bottom)
292       .layoutWeight(1)
293     }
294   }
295 }
296 ```
297 
298 ## 相关实例
299 
300 针对可变帧率的开发,有以下相关实例可供参考:
301 
302 - [DisplaySync分级管控(ArkTS)(API11)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Graphics/DisplaySync)