轻松上手-骨架屏后动画显示
精华作者:狼哥 团队:坚果派 团队介绍:坚果派由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉。团队成员聚集在北京,上海,南京,深圳,广州,宁夏等地,目前已开发鸿蒙原生应用,三方库60+,欢迎交流。
介绍
 在移动应用开发中,采用骨架屏(Skeleton Screen)作为加载策略,具有显著的优势。首先,骨架屏能够即时反馈给用户页面正在加载中,有效缓解了因网络延迟或数据处理造成的“白屏”现象,提升了用户体验的流畅度与期待感。它以一种轻量级、占位符的形式预先展示页面结构,让用户对即将呈现的内容有所预期,减少了等待时的焦虑感。
 其次,骨架屏设计简洁且高度自定义,能够根据应用风格和页面布局灵活调整,保持界面的一致性和美观性。这种视觉上的连续性不仅增强了应用的品牌形象,也提升了用户对产品的信任度和好感度。
 再者,从性能优化的角度来看,骨架屏相比完整的页面内容加载更快,因为它仅包含基础的框架结构和动画效果,减少了初始加载的数据量,有助于提升应用的加载速度和响应能力。这对于提升用户留存率和转化率具有重要意义。
 综上所述,骨架屏作为现代移动应用设计中的一种高效加载策略,以其即时反馈、美化等待体验、提升性能及增强品牌一致性等优势,成为提升用户体验不可或缺的一环。
效果预览
|  |  | 
|---|---|
|  |  | 
|  |  | 
|  |  | 
知识点
1. 显式动画 (animateTo)
2. 组件内转场 (transition)
3. if/else:条件渲染
4. ForEach:循环渲染
工程目录
├──entry/src/main/ets                        // 代码区
│  ├──components
│  │  └──TextAreaBuilder.ets				 // 骨架屏占位组件 
│  ├──entryability
│  │  └──EntryAbility.ets 
│  ├──pages
│  │  └──Index.ets                           // 首页
│  └──view
│     ├──GridSkeleton.ets              		 // Grid骨架图
│     ├──GridView.ets                 		 // Grid布局图
│     ├──ListSkeleton.ets                 	 // List骨架图
│     └──ListView.ets                  		 // List布局图
│     ├──SwiperSkeleton.ets                  // Swiper骨架图
│     └──SwiperView.ets                 	 // Swiper布局图
└──entry/src/main/resources                  // 应用资源目录
具体实现
 在HarmonyOS(鸿蒙系统)中实现骨架屏(Skeleton Screen)通常用于提升应用的加载体验,特别是在网络请求数据尚未返回时显示一个大致的页面框架,让用户知道页面正在加载中。下面介绍如何使用if/else渲染、foreach渲染、显式动画以及组件内转场等技术在HarmonyOS中实现骨架屏。
 骨架屏基础设计
 设计你的骨架屏布局。骨架屏通常包括简单的线条、圆形等,以模拟最终加载完成后的页面结构。可以使用在TextAreaBuilder.ets里封装的textArea Builder来创建。
1. 骨架屏占位组件
@Builder
export function textArea(
  width: number | Resource | string = '100%',
  height: number | Resource | string = '100%',
  borderRadius: Length | BorderRadiuses | LocalizedBorderRadiuses = 0,
  padding: Length | Padding | LocalizedPadding = 0,
  margin: Length | Padding | LocalizedPadding = 0) {
  Row()
    .width(width)
    .height(height)
    .backgroundColor('#FFF2F3F4')
    .borderRadius(borderRadius)
    .padding(padding)
    .margin(margin)
}
2. 首页
 首页由Swiper视图、Grid视图、List视图组成,各自布局和逻辑在各自上实现。
@Entry
@Component
struct Index {
    build() {
    Column({ space: 20 }) {
      SwiperView()
      GridView()
      ListView()
    }
    .height('100%')
    .width('100%')
  }
}
3. Swiper实现
 Swiper骨架图
import { textArea } from '../components/TextAreaBuilder'
@Component
export struct SwiperSkeleton {
  build() {
    textArea('90%', px2vp(460), 16, 0, {top: 11})
  }
}
 Swiper实现与布局
@State isLoadingSwiperData: boolean = true;
aboutToAppear(): void {
  // 模拟异步回调
  setTimeout(() => {
    animateTo({ duration: 1000 }, () => {
      this.isLoadingSwiperData = false;
    })
  }, 4000)
}
Swiper() {
  ForEach(this.bannerList, (item: BannerClass) => {
    if (this.isLoadingSwiperData) {
      SwiperSkeleton()
    } else {
      Image($r(item.imageSrc))
        .objectFit(ImageFit.Contain)
        .width('100%')
        .borderRadius(16)
        .transition({ type: TransitionType.Insert, translate: { x: 700, y: 0 } })
    }
  }, (item: BannerClass) => item.id.toString())
}
4. Grid实现
 Grid骨架图
import { textArea } from '../components/TextAreaBuilder'
@Component
export struct GridSkeleton {
  build() {
    Column({space: 15}) {
      textArea('100%', '60%', { topLeft: 16, topRight: 16 })
      Column({space: 15}) {
        textArea('60%', '15%')
        textArea('90%', '25%')
      }
      .width('100%')
      .alignItems(HorizontalAlign.Start)
      .padding({left: 15})
    }
    .height('100%')
    .width('100%')
    .alignItems(HorizontalAlign.Start)
  }
}
 Grid实现与布局
@State isLoadingGridData: boolean = true;
aboutToAppear(): void {
  // 模拟异步回调
  setTimeout(() => {
    animateTo({ duration: 3000 }, () => {
      this.isLoadingGridData = false;
    })
  }, 6000)
}
  Grid() {
    ForEach(this.enablementList, (item: ArticleClass) => {
      GridItem() {
        if (this.isLoadingGridData) {
          GridSkeleton()
        } else {
          EnablementItem({ enablementItem: item })
            .transition({ type: TransitionType.Insert, translate: { x: -700, y: 0 } })
        }
      }
      .width(160)
    }, (item: ArticleClass) => item.id.toString())
  }
5. List实现
 List骨架图
import { textArea } from '../components/TextAreaBuilder'
@Component
export struct ListSkeleton {
  build() {
    Row({space: 10}) {
      Column({space: 10}) {
        textArea('60%', '20%')
        textArea('90%', '70%')
      }
      .width('70%')
      .alignItems(HorizontalAlign.Start)
      textArea('30%', '100%', 16)
    }
    .height(88)
    .margin({ bottom: 10 })
    .justifyContent(FlexAlign.SpaceBetween)
  }
}
 List实现与布局
@State isLoadingListData: boolean = true;
aboutToAppear(): void {
  // 模拟异步回调
  setTimeout(() => {
    animateTo({ duration: 3000 }, () => {
      this.isLoadingListData = false;
    })
  }, 8000)
}
List({ space: 12 }) {
    ForEach(this.tutorialList, (item: ArticleClass) => {
      ListItem() {
        if (this.isLoadingListData) {
          ListSkeleton()
        } else {
          TutorialItem({ tutorialItem: item })
            .transition({ type: TransitionType.Insert, translate: { x: 0, y: 500 } })
        }
      }
    }, (item: ArticleClass) => item.id.toString())
  }
总结
 通过此案例,可以学习到显式动画知识点,全局animateTo显式动画接口来指定由于闭包代码导致的状态变化插入过渡动效。同属性动画,布局类改变宽高的动画,内容都是直接到终点状态。组件内转场主要通过transition属性配置转场参数,在组件插入和删除时显示过渡动效,主要用于容器组件中的子组件插入和删除时,提升用户体验。if/else条件渲染,可根据应用的不同状态,使用if、else和else if渲染对应状态下的UI内容。ForEach循环渲染,ForEach接口基于数组类型数据来进行循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在ForEach父容器组件中的子组件。例如,ListItem组件要求ForEach的父容器组件必须为List组件。总之,以后在很多异步返回数据前,都可以先显示骨架屏,让用户知道页面正在加载中,在HarmonyOS中实现骨架屏需要结合布局设计、数据绑定、条件渲染、动画以及可能的组件内状态管理。
约束与限制
1.本示例仅支持标准系统上运行,支持设备:华为手机。
2.HarmonyOS系统:HarmonyOS NEXT Developer Beta1及以上。
3.DevEco Studio版本:DevEco Studio NEXT Developer Beta1及以上。
4.HarmonyOS SDK版本:HarmonyOS NEXT Developer Beta1 SDK及以上。
- 3回答
- 8粉丝
- 2关注
- 鸿蒙next团结引擎适配轻松上手
- 轻松上手-Navigation路由H5
- 小白必看 HarmonyOS Next HMRouter 轻松上手秘籍
- 三文带你轻松上手鸿蒙的AI语音01-实时语音识别
- 三文带你轻松上手鸿蒙的AI语音03-文本合成声音
- 轻松上手-MVVM_关系型数据库_云函数T云数据库
- 三文带你轻松上手鸿蒙的AI语音02-声音文件转文本
- uniapp 极速上手鸿蒙开发
- 鸿蒙Next显示动画animateTo介绍
- 模拟器快速上手,助力HarmonyOS应用/服务高效开发
- 三天上手仓颉编程语言开发:极速入门指南
- 鸿蒙HarmonyOS入门学习竟如此简单,如何三天上手鸿蒙应用开发
- PurplePi :最便宜的OpenHarmony5.0标准系统开源开发板上手体验
- 关于bindsheet在横屏、2in1下显示不正常的情况及解决方案##ArkTS##
- 鸿蒙开发:DevEco Studio中截屏和录屏功能

