背景
在应用开发中,Swiper 组件常用于翻页场景,比如:桌面、图库等应用。Swiper 组件滑动切换页面时,基于按需加载原则通常会在下一个页面将要显示时才对该页面进行加载和布局绘制,这个过程包括:
- 如果该页面使用了@Component 装饰的自定义组件,那么自定义组件的 build 函数会被执行并创建内部的 UI 组件;
- 如果使用了LazyForEach,会执行 LazyForEach 的 UI 生成函数生成 UI 组件;
- 在 UI 组件构建完成后,会对 UI 组件进行布局测算和绘制。
针对复杂页面场景,该过程可能会持续较长时间,导致滑动过程中出现卡顿,对滑动体验造成负面影响,甚至成为整个应用的性能瓶颈。如在图库大图浏览场景中,若不使用预加载机制,每次都将在滑动开始的首帧去加载下一张图片,会导致首帧耗时过长甚至掉帧,拖慢应用性能。
为了解决上述问题,可以使用 Swiper 组件的预加载机制,利用主线程的空闲时间来提前构建和布局绘制组件,优化滑动体验。
使用场景
如果开发者的应用场景属于加载较为耗时的场景时,尤其是下列场景,推荐使用 Swiper 预加载功能。
- Swiper 的子组件大于等于五个;
- Swiper 的子组件具有复杂的动画;
- Swiper 的子组件加载时需要执行网络请求等耗时操作;
- Swiper 的子组件包含大量需要渲染的图像或资源。
Swiper 预加载机制说明
预加载机制是 Swiper 组件中一个重要的特性,允许 Swiper 滑动到下一个子组件之前提前加载后续页面的内容,其主要目的是提高应用滑动时的流畅性和响应速度。当用户尝试滑动到下一个子组件时,如果下一个子组件的内容已经提前加载完毕,那么滑动就会立即发生,否则 Swiper 组件需要在加载下一个子组件的同时处理滑动事件,对滑动体验造成负面影响。当前 Swiper 组件的预加载在用户滑动离手动效开始时触发,离手动效的计算在渲染线程中进行,因此主线程有空闲的时间可以进行预加载的操作。配合 LazyForEach 的按需加载和销毁能力,可以在优化滑动体验基础上节省内存占用。
使用指导
- 预加载子组件的个数在cachedCount属性中配置。
Swiper 共 5 页,当开发者设置了 cacheCount 属性为 1 且 loop 属性为 false 时,预加载的结果如下:
Swiper 共 5 页,当开发者设置了 cacheCount 属性为 1 且 loop 属性为 true 时,预加载的结果如下:
- Swiper 组件的子组件使用LazyForEach动态加载和销毁组件。
示例
class MyDataSource implements IDataSource {
// LazyForEach的数据源
private list: number[] = [];
constructor(list: number[]) {
this.list = list;
}
totalCount(): number {
return this.list.length;
}
getData(index: number): number {
return this.list[index];
}
registerDataChangeListener(_: DataChangeListener): void {
}
unregisterDataChangeListener(): void {
}
}
@Component
struct SwiperChildPage {
// Swiper的子组件
@State arr: number[] = [];
aboutToAppear(): void {
for (let i = 1; i <= 100; i++) {
this.arr.push(i);
}
}
build() {
Column() {
List({
space: 20 }) {
ForEach(this.arr, (index: number) => {
ListItem() {
Text(index.toString())
.height('4.5%')
.fontSize(16)
.textAlign(TextAlign.Center)
.backgroundColor(0xFFFFFF)
}
.border({
width: 2, color: Color.Green })