案例:自定义下拉刷新动画(ArkTS)

2024-01-10 10:40:58

介绍

在这里插入图片描述

本篇Codelab主要介绍组件动画animation属性设置。当组件的某些通用属性变化时,可以通过属性动画实现渐变效果,提升用户体验。

本Codelab使用的display接口处于mock阶段,在预览器上使用会显示白屏现象,可选择在真机或模拟器上运行。

相关概念

  • 属性动画:组件的某些通用属性变化时,可以通过属性动画实现渐变效果,提升用户体验。支持的属性包括width、height、backgroundColor、opacity、scale、rotate、translate等。案例中自定义头部组件的属性动画设置主要涉及duration(动画时长)、tempo(动画速率)、delay(动画延时)、curve(动画曲线)、palyMode(动画模式)和iterations(动画播放次数)。

完整示例

gitee源码地址

源码下载

自定义下拉刷新动画(ArkTS).zip

代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载或gitee中提供。

├──entry/src/main/ets                      // 代码区           
│  ├──common
│  │  ├──constants                     
│  │  │  ├──CommonConstants.ets            // 公共常量类
│  │  │  └──RefreshConstants.ets           // 下拉刷新常量类
│  │  └──utils                 
│  │     ├──DimensionUtil.ets              // 屏幕适配工具类
│  │     └──GlobalContext.ets              // 全局上下文工具类
│  ├──entryability
│  │  └──EntryAbility.ets                  // 程序入口类
│  ├──pages
│  │  ├──FileManagerIndex.ets              // 文件管理Tab页
│  │  └──TabIndex.ets                      // Tab管理页
│  ├──view
│  │  ├──RefreshAnimHeader.ets             // 动画刷新组件
│  │  ├──RefreshComponent.ets              // 下拉刷新组件
│  │  └──RefreshDefaultHeader.ets          // 默认刷新组件
│  └──viewmodel
│     ├──AnimationModel.ets                // 动画封装类
│     └──CardModel.ets                     // 页签封装类
└──entry/src/main/resources                // 资源文件目录

自定义下拉组件

自定义下拉刷新通过自定义List组件RefreshComponent实现。在List容器中添加自定义刷新头部组件和其它的需要刷新部件,RefreshComponent提供了头部样式设置,刷新部件样式设置和刷新回调方法设置。

// FileManagerIndex.ets
RefreshComponent({
  headerStyle: RefreshHeaderStyle.CLOUD, // 头部样式设置
  itemLayout: (): void => this.ContentBody(), // 刷新部件样式
  displayHeight: (
    px2vp(this.deviceDisplay.height) - DimensionUtil.getVp($r('app.float.file_index_title_height'))),
  onRefresh: () => { // 刷新回调方法
    ...
  }
})
  • 头部样式设置。本Codelab提供了DEFAULT默认刷新样式和CLOUD云朵动画刷新样式设置,在RefreshComponent组件初始化时,判断当前刷新样式进行渲染。
// RefreshComponent.ets
if (this.headerStyle === RefreshHeaderStyle.DEFAULT) {
  RefreshDefaultHeader().height(RefreshConstants.REFRESH_HEADER_HEIGHT)
} else if (this.headerStyle === RefreshHeaderStyle.CLOUD) {
  RefreshAnimHeader().height(RefreshConstants.REFRESH_HEADER_HEIGHT)
}
  • 刷新部件样式。刷新部件样式itemLayout为嵌入RefreshComponent组件中的元素,通过@BuilderParam装饰符定义,可根据具体业务需求,当前为默认的Image组件样式。
// FileManagerIndex.ets
@Builder
ContentBody() {
  Image($r('app.media.bg_content'))
    .width(CommonConstants.FULL_LENGTH)
    .height(DimensionUtil.getVp($r('app.float.content_height')))
    .objectFit(ImageFit.Fill)
}
  • 刷新回调方法设置。在手指拖拽刷新头部滑出的过程中计算滑出的距离是否超出可刷新距离,松开手指时如果超出可刷新距离则调用“onRefresh”方法。
// RefreshComponent.ets
// 设置RefreshComponent刷新组件state状态的更新。
@Consume(RefreshConstants.REFRESH_STATE_TAG) @Watch('onStateChanged') state: number;

private onStateChanged() {
  switch (this.state) {
    case RefreshState.REFRESHING:
      if (this.onRefresh !== undefined) {
        this.onRefresh();
      }
      break;
    ...
  }
}

// 监听RefreshComponent中List组件的触摸事件。
List({ scroller: this.listController }) {
  ListItem() {
    Column() {
      ...
    }
    ...
  }
}
...
.onTouch((event?: TouchEvent) => {
  if (!event) {
    return;
  }
  switch (event.type) {
    case TouchType.Down:
      if (this.state === RefreshState.IDLE) {
        this.state = RefreshState.DRAGGING;
      }
      break;
    case TouchType.Move:
      if (this.state === RefreshState.DRAGGING
      && this.listController.currentOffset().yOffset <= -RefreshConstants.REFRESH_EFFECTIVE_HEIGHT) {
        this.state = RefreshState.DRAGGING_REFRESHABLE;
      }
      break;
    case TouchType.Up:
      if (this.state === RefreshState.DRAGGING_REFRESHABLE) {
        this.headerOffset = 0;
        this.state = RefreshState.REFRESHING;
      }
      break;
    default:
      break;
}

// FileManagerIndex.ets
//onRefresh事件没有做相关刷新,只做了模拟延时操作,开发者可以自行加入真实网络加载动作。
onRefresh: () => {
  setTimeout(() => {
    this.state = RefreshState.COMPLETE;
  }, CommonConstants.REFRESH_DEFAULT_TIMEOUT);
}

自定义刷新动画

本Codelab中自定义刷新是由5个图片的组合动画效果。

  • 每个Image通过iconItem参数分别设置各自的x轴偏移量和延时播放的属性动画效果。
// RefreshAnimHeader.ets
@Builder AttrAnimIcons(iconItem: ClassifyModel) {
  Image(iconItem.imgRes)
    .width(px2vp(DimensionUtil.adaptDimension(this.iconWidth)))
    .position({ x: iconItem.posX })
    .objectFit(ImageFit.Contain)
    .animation({
      duration: CommonConstants.REFRESH_HEADER_ITEM_ANIM_DURATION,
      tempo: CommonConstants.REFRESH_HEADER_ITEM_ANIM_TEMPO,
      delay: iconItem.delay,
      curve: Curve.Linear,
      playMode: PlayMode.Alternate,
      iterations: CommonConstants.REFRESH_HEADER_ITEM_ANIM_ITERATIONS
    })
}
  • 监听RefreshComponent刷新组件state状态的变化,当前状态为REFRESHING状态时,改变@State修饰的图片宽度变量iconWidth来启动动画。
// RefreshAnimHeader.ets
@Consume(RefreshConstants.REFRESH_STATE_TAG) @Watch('onStateCheck') state: number;

private onStateCheck() {
  if (this.state === RefreshState.REFRESHING) {
    this.iconWidth = CommonConstants.REFRESH_HEADER_ITEM_SCALE_WIDTH;
  } else {
    this.iconWidth = CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH;
  }
}

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. 使用属性动画实现自定义下拉组件。
  2. 使用属性动画实现自定义刷新组件。

文章来源:https://blog.csdn.net/qq_36067302/article/details/135469632
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。