轻松上手-骨架屏后动画显示

markdown 复制代码
作者:狼哥
团队:坚果派
团队介绍:坚果派由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉。团队成员聚集在北京,上海,南京,深圳,广州,宁夏等地,目前已开发鸿蒙原生应用,三方库60+,欢迎交流。

介绍

​ 在移动应用开发中,采用骨架屏(Skeleton Screen)作为加载策略,具有显著的优势。首先,骨架屏能够即时反馈给用户页面正在加载中,有效缓解了因网络延迟或数据处理造成的"白屏"现象,提升了用户体验的流畅度与期待感。它以一种轻量级、占位符的形式预先展示页面结构,让用户对即将呈现的内容有所预期,减少了等待时的焦虑感。

​ 其次,骨架屏设计简洁且高度自定义,能够根据应用风格和页面布局灵活调整,保持界面的一致性和美观性。这种视觉上的连续性不仅增强了应用的品牌形象,也提升了用户对产品的信任度和好感度。

​ 再者,从性能优化的角度来看,骨架屏相比完整的页面内容加载更快,因为它仅包含基础的框架结构和动画效果,减少了初始加载的数据量,有助于提升应用的加载速度和响应能力。这对于提升用户留存率和转化率具有重要意义。

​ 综上所述,骨架屏作为现代移动应用设计中的一种高效加载策略,以其即时反馈、美化等待体验、提升性能及增强品牌一致性等优势,成为提升用户体验不可或缺的一环。

效果预览

知识点

1. 显式动画 (animateTo)
2. 组件内转场 (transition)
3. if/else:条件渲染
4. ForEach:循环渲染

工程目录

typescript 复制代码
├──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. 骨架屏占位组件
typescript 复制代码
@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视图组成,各自布局和逻辑在各自上实现。

typescript 复制代码
@Entry
@Component
struct Index {
    build() {
    Column({ space: 20 }) {
      SwiperView()
      GridView()
      ListView()
    }
    .height('100%')
    .width('100%')
  }
}
3. Swiper实现

​ Swiper骨架图

typescript 复制代码
import { textArea } from '../components/TextAreaBuilder'
@Component
export struct SwiperSkeleton {
  build() {
    textArea('90%', px2vp(460), 16, 0, {top: 11})
  }
}

​ Swiper实现与布局

typescript 复制代码
  @State isLoadingSwiperData: boolean = true;
  aboutToAppear(): void {
    // 模拟异步回调
    setTimeout(() => {
      animateTo({ duration: 1000 }, () => {
        this.isLoadingSwiperData = false;
      })
    }, 4000)
  }
typescript 复制代码
  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骨架图

typescript 复制代码
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实现与布局

typescript 复制代码
  @State isLoadingGridData: boolean = true;
  aboutToAppear(): void {
    // 模拟异步回调
    setTimeout(() => {
      animateTo({ duration: 3000 }, () => {
        this.isLoadingGridData = false;
      })
    }, 6000)
  }
typescript 复制代码
  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骨架图

typescript 复制代码
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实现与布局

typescript 复制代码
  @State isLoadingListData: boolean = true;
  aboutToAppear(): void {
    // 模拟异步回调
    setTimeout(() => {
      animateTo({ duration: 3000 }, () => {
        this.isLoadingListData = false;
      })
    }, 8000)
  }
typescript 复制代码
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及以上。

相关推荐
别说我什么都不会11 小时前
ohos.net.http请求HttpResponse header中set-ccokie值被转成array类型
网络协议·harmonyos
码是生活11 小时前
鸿蒙开发排坑:解决 resourceManager.getRawFileContent() 获取文件内容为空问题
前端·harmonyos
鸿蒙场景化示例代码技术工程师11 小时前
基于Canvas实现选座功能鸿蒙示例代码
华为·harmonyos
小脑斧爱吃鱼鱼12 小时前
鸿蒙项目笔记(1)
笔记·学习·harmonyos
鸿蒙布道师13 小时前
鸿蒙NEXT开发对象工具类(TS)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
zhang10620913 小时前
HarmonyOS 基础组件和基础布局的介绍
harmonyos·基础组件·基础布局
马剑威(威哥爱编程)13 小时前
在HarmonyOS NEXT 开发中,如何指定一个号码,拉起系统拨号页面
华为·harmonyos·arkts
GeniuswongAir15 小时前
Flutter极速接入IM聊天功能并支持鸿蒙
flutter·华为·harmonyos
90后的晨仔18 小时前
鸿蒙ArkUI框架中的状态管理
harmonyos
别说我什么都不会1 天前
OpenHarmony 5.0(API 12)关系型数据库relationalStore 新增本地数据变化监听接口介绍
api·harmonyos