HarmonyOS鸿蒙Next中ArkTS如何实现骨架屏(Skeleton Loading)效果?

HarmonyOS鸿蒙Next中ArkTS如何实现骨架屏(Skeleton Loading)效果? 在 ArkTS 中如何实现骨架屏(Skeleton Loading)效果,列表加载时显示灰色占位块,提升用户体验。

7 回复

开发者您好,如下提供LazyForEach实现骨架屏预加载的方案:

【解决方案】

  1. 使用LazyForEach对数据源中的每个数据进行预加载。
  2. 在Stack组件中,首先设置背景色为rgba(0,0,0,0.1),然后通过linearGradient设置组件的颜色渐变效果,并结合animation方法设置动画的持续时间和循环次数。
// 用户自定义数据源
class MyDataSourceLOne implements IDataSource {
  private list: number[] = [];

  constructor(list: number[]) {
    this.list = list;
  }

  totalCount(): number {
    return this.list.length;
  }

  getData(index: number): number {
    return this.list[index];
  }

  registerDataChangeListener(): void {
  }

  unregisterDataChangeListener() {
  }
}

@Entry
@Component
struct BackGroundColorGradualChange {
  private arr: MyDataSourceLOne = new MyDataSourceLOne([]);
  private listScroller: ListScroller = new ListScroller();
  @State translateX: string = '-100%';

  aboutToAppear(): void {
    let list: number[] = [];
    for (let i = 1; i <= 7; i++) {
      list.push(i);
    }
    this.arr = new MyDataSourceLOne(list);
  }

  build() {
    Column() {
      List({ space: 20, initialIndex: 100, scroller: this.listScroller }) {
        LazyForEach(this.arr, () => {
          ListItem() {
            Stack() {
              // 设置组件的背景色
              Text()
                .width('100%')
                .height(100)
                .backgroundColor('rgba(0,0,0,0.1)');

              Text()
                .width('100%')
                .height(100)
                .translate({ x: this.translateX })
                .onAppear(() => {
                  this.translateX = '100%';
                })
                // 设置动画的持续时间和循环次数
                .animation({
                  duration: 1500,
                  iterations: -1
                })
                // 设置颜色渐变效果
                .linearGradient({
                  angle: 90,
                  colors: [
                    ['rgba(255,255,255,0)', 0],
                    ['rgba(255,255,255,1)', 0.5],
                    ['rgba(255,255,255,0)', 1]
                  ]
                });
            }
            .width('100%')
            .height(100)
            .backgroundColor(0xFFFFFF);
          };
        });
      }
      .listDirection(Axis.Vertical)
      .scrollBar(BarState.Off)
      .friction(0.6)
      .edgeEffect(EdgeEffect.Spring)
      .width('90%')
      .cachedCount(3);
    }
    .width('100%')
    .height('100%')
    .backgroundColor(0xDCDCDC)
    .padding({ top: 5 });
  }
}

【背景知识】

  • LazyForEach为开发者提供了基于数据源渲染出一系列子组件的能力。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会销毁并回收组件以降低内存占用。
  • 骨架屏通过显示简单的灰色块和线条,让用户在等待内容加载时获得视觉反馈。

更多关于HarmonyOS鸿蒙Next中ArkTS如何实现骨架屏(Skeleton Loading)效果?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


1、参考官网案例:【LazyForEach实现骨架屏预加载效果】

2、使用三方的骨架屏组件:【骨架屏组件】

cke_692.png

基本实现步骤

1. 定义加载状态变量

@State isLoading: boolean = true;

2. 编写骨架屏组件(可复用)

@Component
struct SkeletonItem {
  build() {
    Column() {
      // 标题骨架
      Row()
        .width('80%')
        .height(20)
        .backgroundColor('#e0e0e0')
        .borderRadius(4)

      // 内容骨架
      Row()
        .width('100%')
        .height(16)
        .margin({ top: 8 })
        .backgroundColor('#e0e0e0')
        .borderRadius(4)

      Row()
        .width('60%')
        .height(16)
        .margin({ top: 4 })
        .backgroundColor('#webtoken')
        .borderRadius(4)
    }
    .padding(16)
    .backgroundColor('#f5f5f5')
    .borderRadius(8)
  }
}

3. 在主页面中根据状态切换显示

@Entry
@Component
struct MainPage {
  @State isLoading: boolean = true;
  private data: string = '';

  aboutToAppear() {
    // 模拟网络请求
    setTimeout(() => {
      this.data = '加载完成的内容';
      this.isLoading = false;
    }, 2000);
  }

  build() {
    Column() {
      if (this.isLoading) {
        // 显示骨架屏
        Column() {
          ForEach(Array(3), (_, index) => {
            SkeletonItem()
              .margin({ bottom: 12 })
          })
        }
        .padding(16)
      } else {
        // 显示真实内容
        Text(this.data)
          .fontSize(18)
          .padding(16)
      }
    }
    .width('100%')
    .height('100%')
  }
}

在HarmonyOS Next中,ArkTS可通过@Builder装饰器构建骨架屏组件。主要步骤包括:使用ColumnRow等布局容器模拟内容结构,通过Rectangle组件绘制占位块,并设置其宽度、高度、圆角及背景色(通常为浅灰色)。利用@State装饰的状态变量控制骨架屏的显示与隐藏。加载数据时显示骨架屏,数据加载完成后切换为实际内容。可通过animation属性添加简单的透明度或平移动画增强视觉效果。

在HarmonyOS Next的ArkTS中,可以通过以下方式实现骨架屏效果:

1. 使用条件渲染控制显示

// 数据加载状态
@State isLoading: boolean = true
@State listData: Array<Object> = []

// 模板部分
if (this.isLoading) {
  // 显示骨架屏
  SkeletonView()
} else {
  // 显示实际内容
  RealContentView()
}

2. 创建骨架屏组件

@Component
struct SkeletonItem {
  build() {
    Column() {
      // 头像占位
      Row()
        .width(80)
        .height(80)
        .backgroundColor('#E0E0E0')
        .borderRadius(40)
      
      // 文本占位
      Column() {
        Row()
          .width('60%')
          .height(20)
          .backgroundColor('#E0E0E0')
          .margin({ top: 10 })
        
        Row()
          .width('40%')
          .height(15)
          .backgroundColor('#E0E0E0')
          .margin({ top: 8 })
      }
    }
    .padding(12)
  }
}

3. 添加加载动画效果

// 使用动画增强效果
@State opacityValue: number = 0.5

aboutToAppear() {
  // 创建脉动动画
  setInterval(() => {
    this.opacityValue = this.opacityValue === 0.5 ? 0.8 : 0.5
  }, 1000)
}

// 在骨架屏元素上应用
Row()
  .opacity(this.opacityValue)
  .animation({ duration: 1000, curve: Curve.EaseInOut })

4. 列表骨架屏实现

@Component
struct SkeletonList {
  build() {
    List() {
      ForEach(Array.from({ length: 5 }), (item, index) => {
        ListItem() {
          SkeletonItem()
        }
      })
    }
  }
}

5. 实际应用示例

@Component
struct ContentPage {
  @State isLoading: boolean = true
  @State dataList: Array<any> = []
  
  aboutToAppear() {
    // 模拟数据加载
    setTimeout(() => {
      this.dataList = this.fetchData()
      this.isLoading = false
    }, 2000)
  }
  
  build() {
    Column() {
      if (this.isLoading) {
        SkeletonList()
      } else {
        RealList({ data: this.dataList })
      }
    }
  }
}

关键要点:

  • 使用条件渲染切换骨架屏和真实内容
  • 骨架屏样式应模拟真实内容的布局结构
  • 可添加淡入淡出或脉动动画提升体验
  • 保持骨架屏与真实内容的尺寸一致
  • 在数据加载完成后平滑过渡到真实内容

这种实现方式能有效提升加载时的用户体验,避免页面空白或布局跳动。

回到顶部