1# 合理使用动画 2 3本文列举了部分用于优化动画时延的正反案例,帮助开发者在遇到相似场景时进行优化,解决构建页面动画时遇到动画时延较长的问题。 4 5## 减少动画丢帧 6 7在播放动画或者生成动画时,画面产生停滞而导致帧率过低的现象,称为动画丢帧。 8 9播放动画时,系统需要在一个刷新周期内完成动画变化曲线的计算,完成组件布局绘制等操作。建议使用系统提供的动画接口,只需设置曲线类型、终点位置、时长等信息,就能够满足常用的动画功能,减少UI主线程的负载。 10 11反例:应用使用了自定义动画,动画曲线计算过程很容易引起UI线程高负载,易导致丢帧。 12 13```typescript 14@Entry 15@Component 16struct AttrAnimationExample0 { 17 @State widthSize: number = 200 18 @State heightSize: number = 100 19 @State flag: boolean = true 20 21 computeSize() { 22 let duration = 2000 23 let period = 16 24 let widthSizeEnd = 0 25 let heightSizeEnd = 0 26 if (this.flag) { 27 widthSizeEnd = 100 28 heightSizeEnd = 50 29 } else { 30 widthSizeEnd = 200 31 heightSizeEnd = 100 32 } 33 let doTimes = duration / period 34 let deltaHeight = (heightSizeEnd - this.heightSize) / doTimes 35 let deltaWeight = (widthSizeEnd - this.widthSize) / doTimes 36 for (let i = 1; i <= doTimes; i++) { 37 let t = period * (i); 38 setTimeout(() => { 39 this.heightSize = this.heightSize + deltaHeight 40 this.widthSize = this.widthSize + deltaWeight 41 }, t) 42 } 43 this.flag = !this.flag 44 } 45 46 build() { 47 Column() { 48 Button('click me') 49 .onClick(() => { 50 let delay = 500 51 setTimeout(() => { this.computeSize() }, delay) 52 }) 53 .width(this.widthSize).height(this.heightSize).backgroundColor(0x317aff) 54 }.width('100%').margin({ top: 5 }) 55 } 56} 57``` 58 59 60 61### 使用系统提供的属性动效API 62 63建议:通过系统提供的属性动效API实现上述动效功能。 64 65```typescript 66@Entry 67@Component 68struct AttrAnimationExample1 { 69 @State widthSize: number = 200 70 @State heightSize: number = 100 71 @State flag: boolean = true 72 73 build() { 74 Column() { 75 Button('click me') 76 .onClick((event?: ClickEvent | undefined) => { 77 if (this.flag) { 78 this.widthSize = 100 79 this.heightSize = 50 80 } else { 81 this.widthSize = 200 82 this.heightSize = 100 83 } 84 this.flag = !this.flag 85 }) 86 .width(this.widthSize).height(this.heightSize).backgroundColor(0x317aff) 87 .animation({ 88 duration: 2000, // 动画时长 89 curve: Curve.Linear, // 动画曲线 90 delay: 500, // 动画延迟 91 iterations: 1, // 播放次数 92 playMode: PlayMode.Normal // 动画模式 93 }) // 对Button组件的宽高属性进行动画配置 94 }.width('100%').margin({ top: 5 }) 95 } 96} 97``` 98 99 100 101更详细的API文档请参考:[属性动画](../reference/apis-arkui/arkui-ts/ts-animatorproperty.md)。 102 103### 使用系统提供的显式动效API 104 105建议:通过系统提供的显式动效API实现上述动效功能。 106 107```typescript 108@Entry 109@Component 110struct AnimateToExample2 { 111 @State widthSize: number = 200; 112 @State heightSize: number = 100; 113 @State flag: boolean = true; 114 115 build() { 116 Column() { 117 Button('click me') 118 .onClick((event?: ClickEvent | undefined) => { 119 if (this.flag) { 120 animateTo({ 121 duration: 2000, // 动画时长 122 curve: Curve.Linear, // 动画曲线 123 delay: 500, // 动画延迟 124 iterations: 1, // 播放次数 125 playMode: PlayMode.Normal // 动画模式 126 }, () => { 127 this.widthSize = 100; 128 this.heightSize = 50; 129 }) 130 } else { 131 animateTo({ 132 duration: 2000, // 动画时长 133 curve: Curve.Linear, // 动画曲线 134 delay: 500, // 动画延迟 135 iterations: 1, // 播放次数 136 playMode: PlayMode.Normal // 动画模式 137 }, () => { 138 this.widthSize = 200; 139 this.heightSize = 100; 140 }) 141 } 142 this.flag = !this.flag; 143 }) 144 .width(this.widthSize).height(this.heightSize).backgroundColor(0x317aff) 145 }.width('100%').margin({ top: 5 }) 146 } 147} 148``` 149 150 151 152更详细的API文档请参考:[显式动画](../reference/apis-arkui/arkui-ts/ts-explicit-animation.md)。 153 154### 优化效果 155 156相比于自定义动画,使用系统提供的动效API可提高动画帧数,提高应用性能。 157 158| 动画实现方式 | 帧数(fps) | 159|---------|---------| 160| 自定义动画 | 60 | 161| 属性动效API | 120 | 162| 显式动效API | 120 | 163 164## 合理设置隐式动画 165 166Tabs组件在不为BottomTabBarStyle样式时,切换页面时默认加载300ms的隐式动画,如果开发场景不需要该动画效果,会因默认加载导致页面跳转完成时延变长,此时可手动设置`animationDuration`减少动画完成时延。下述正反示例分别为100ms和1000ms的动画时延: 167 168### 反例: 169 170```javascript 171@Entry 172@Component 173struct TabsExample { 174 // ... 175 private controller: TabsController = new TabsController(); 176 177 build() { 178 Column() { 179 Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) { 180 TabContent() 181 TabContent() 182 // ... 183 } 184 // ... 185 // 设置Tabs页面跳转的动画时长为1000ms 186 .animationDuration(1000) 187 } 188 .width('100%') 189 } 190} 191``` 192 193 194 195### 正例: 196 197```javascript 198@Entry 199@Component 200struct TabsExample { 201 // ... 202 private controller: TabsController = new TabsController(); 203 204 build() { 205 Column() { 206 Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) { 207 TabContent() 208 TabContent() 209 // ... 210 } 211 // ... 212 // 设置Tabs页面跳转的动画时长为100ms 213 .animationDuration(100) 214 } 215 .width('100%') 216 } 217} 218``` 219 220 221 222### 优化效果 223 224| 优化前 1000ms | 优化后 100ms | 225|----------------------------------------------------|----------------------------------------------------| 226|  |  | 227 228上述示例通过减少`animationDuration`数值,减少Tabs切换完成时延。当数值设置为0且TabBar不为BottomTabBarStyle样式时,隐式动效延时为默认的300ms。开发者可根据实际场景适当减少隐式动效时延,如果应用没有特殊的动效要求时,建议设置数值为1,减少阻塞主线程,提高应用性能。 229 230更详细的API文档请参考:[Tabs-animationduration](../reference/apis-arkui/arkui-ts/ts-container-tabs.md#animationduration)。 231 232## 合理设置动效时长 233 234滚动类组件可使用**fling**方法按传入的初始速度进行惯性滚动,不合理的滚动速度设置可能导致动效时长过长,此时应通过加快滚动速度减少动效时长。下述正反示例通过改变List组件惯性滚动速度减少动效时长: 235 236### 反例: 237 238```javascript 239@Entry 240@Component 241struct ListExample { 242 scrollerForList: Scroller = new Scroller(); 243 244 build() { 245 Column() { 246 Button('Fling100') 247 .onClick(() => { 248 // 设置当前滚动初始速度为100vp/s 249 this.scrollerForList.fling(100); 250 }) 251 List({ space: 20, initialIndex: 0, scroller: this.scrollerForList }) { 252 // ... 253 } 254 } 255 } 256} 257``` 258 259### 正例: 260 261```javascript 262@Entry 263@Component 264struct ListExample { 265 scrollerForList: Scroller = new Scroller(); 266 267 build() { 268 Column() { 269 Button('Fling100') 270 .onClick(() => { 271 // 设置当前滚动初始速度为10000vp/s 272 this.scrollerForList.fling(10000); 273 }) 274 List({ space: 20, initialIndex: 0, scroller: this.scrollerForList }) { 275 // ... 276 } 277 } 278 } 279} 280``` 281 282### 优化效果 283 284*100vp/s:* 285 286 287 288*10000vp/s:* 289 290 291 292| 示例 | 动效耗时(ms) | 293|-----|----------| 294| 优化前 | 392 | 295| 优化后 | 200 | 296 297上述示例在提高滚动速度到10000vp/s后,相比100vp/s减少了200ms的动画时延。开发者可根据实际场景适当增加滚动速度,在不影响页面效果的情况下减少页面完成时延,提高应用性能。