HarmonyOS鸿蒙开发实战(5.0)网格元素拖动交换案例实践

鸿蒙HarmonyOS开发实战往期必看文章:

HarmonyOS NEXT应用开发性能实践总结

一分钟了解"纯血版!鸿蒙HarmonyOS Next应用开发!

最新版!"非常详细的" 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)


介绍

直接进行交换和删除元素会给用户带来不好的体验效果,因此需要在此过程中注入一些特色的动画来提升体验效果,本案例通过Grid组件、attributeModifier、以 及animateTo函数实现了拖拽动画和删除动画。

效果图预览

使用说明

  1. 进入页面,点击编辑,长按网格元素,执行拖拽操作,拖拽过程中显示此网格元素,拖拽到一定的位置时,会进行网格元素的位置交换。
  2. 编辑模式下,点击首页应用里的网格元素,此元素会被删除,下面对应元素右上角会出现添加标志。
  3. 编辑模式下,点击应用类别1/应用类别2里有添加标识的元素,该元素会在首页应用里出现。

实现思路

本示例主要通过attributeModifier、supportAnimation、animateTo等实现了删除动画以及长按拖拽动画。attributeModifier绑定自定义属性对象, 控制每个网格元素的属性更新。执行删除操作时,通过animateTo去更新offset值以及opacity等属性。supportAnimation设置为true,支持GridItem 拖拽动画,在onItemDragStart开始拖拽网格元素时触发,onItemDragStart可以返回一个@Builder修饰的自定义组件,这样在拖拽的时候, 能够显示目标元素。onItemDrop在网格元素内停止拖拽时触发。此时执行元素位置的切换功能。

  1. 声明一个数组,添加自定义属性对象,每个自定义属性对象对应一个网格元素,源码参考AttributeModifier.etsGridItemDeletionCtrl.ets

    constructor(data: T[]) {
    this.gridData = data;
    data.forEach(() => {
    this.modifier.push(new GridItemModifier());
    })
    }
    /**

    • 声明GridItem动态属性
      */
      @Observed
      export class GridItemModifier implements AttributeModifier<GridItemAttribute> {
      public offsetX: number = 0;
      public offsetY: number = 0;
      public opacity: number = 1;

    /**
    * 定义组件普通状态时的样式
    * @param instance
    */
    applyNormalAttribute(instance: GridItemAttribute): void {
    instance.translate({ x: this.offsetX, y: this.offsetY });
    instance.opacity(this.opacity);
    }
    }

  2. 绑定attributeModifier属性,attributeModifier属性的值为对应的自定义属性对象。源码参考GridExchange.ets

    GridItem() {
    IconWithNameView({ app: item })
    }
    .onAreaChange((oldValue: Area, newValue: Area) => {
    this.itemAreaWidth = Number(newValue.width);
    })
    .onTouch((event: TouchEvent) => {
    if (event.type === TouchType.Down) {
    this.movedItem = this.appInfoList[index];
    }
    })
    // TODO:知识点:动态绑定属性信息
    .attributeModifier(this.GridItemDeletion.getModifier(item) ? this.GridItemDeletion.getModifier(item) : undefined)

  3. 编辑模式下点击网格元素,执行删除操作,删除过程中使用animateTo来更新元素的偏移量并实现动画效果。源码参考GridItemDeletionCtrl.ets

    deleteGridItem(item: T, itemAreaWidth: number): void {
    const index: number = this.gridData.indexOf(item);
    // 最后一条数据不执行偏移
    if (index === this.gridData.length - 1) {
    this.gridData.splice(index, 1);
    this.modifier.splice(index, 1);
    return;
    }
    // TODO:知识点:实现删除动画。先让目标元素的opacity为0,不可视,直接删除目标元素会导致偏移的时候位置异常,接着遍历元素的属性对象,修改偏移量。
    this.modifier[index].opacity = 0;
    animateTo({
    curve: Curve.Friction, duration: ANIMATION_DURATION, onFinish: () => {
    // 初始化偏移位置
    this.modifier.forEach((item) => {
    item.offsetX = 0;
    item.offsetY = 0;
    })
    // 删除对应的数据
    this.gridData.splice(index, 1);
    this.modifier.splice(index, 1);
    this.status = DeletionStatus.FINISH;
    }
    }, () => {
    this.modifier.forEach((item: GridItemModifier, ind: number) => {
    if (ind > index && ind % COLUMN_COUNT !== 0) {
    item.offsetX = -itemAreaWidth;
    } else if (ind > index && ind % COLUMN_COUNT === 0) {
    item.offsetX = itemAreaWidth * 4; // 位置偏移到上一行的最后一列,因此偏移4个gridItem所占的宽度
    item.offsetY = -GRID_ITEM_HEIGHT;
    }
    })
    this.status = DeletionStatus.START;
    })
    }

  4. 交换网格元素,onItemDragStart以及onItemDrop来完成元素的交换功能,supportAnimation设置为true,支持在拖拽时显示动画效果。onItemDragStart函数中 返回目标自定义组件,可以在拖拽过程中显示。onItemDrop函数执行最后网格元素的交换。 源码参考GridExchange.ets

    .supportAnimation(true)
    .editMode(this.isEdit)
    .onItemDragStart((event: ItemDragInfo, itemIndex: number) => {
    // TODO:知识点:在onItemDragStart函数返回自定义组件,可在拖拽过程中显示此自定义组件。
    return this.pixelMapBuilder();
    })
    .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => {
    // TODO:知识点:执行gridItem切换操作
    if (isSuccess && insertIndex < this.appInfoList.length) {
    this.changeIndex(itemIndex, insertIndex);
    }
    })

  5. 编辑模式下,点击有添加标识的网格元素,将其添加到首页应用中,添加过程使用transition来实现动画效果。

    GridItem() {
    IconWithNameView({ app: item })
    }
    // 使用isAddApp控制动画是否显示,只有app添加到首页应用里才显示
    .transition(this.isAddApp ? this.effect : null, () => {
    this.isAddApp = false;
    })

    private effect: TransitionEffect =
    TransitionEffect.OPACITY.animation({
    curve: curves.springMotion(0.6, 0.8)
    })
    // 通过combine方法,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion(0.6, 0.8)
    .combine(TransitionEffect.scale({
    x: 0,
    y: 0
    }))
    // 添加旋转转场效果,这里的动画参数会跟随上面带animation的TransitionEffect,也就是springMotion(0.6, 0.8)
    .combine(TransitionEffect.rotate({ angle: 0 }))
    // 添加平移转场效果,这里的动画参数使用指定的springMotion()
    .combine(TransitionEffect.translate({ x: 150 })
    .animation({ curve: curves.springMotion() }))
    // 添加move转场效果,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion()
    .combine(TransitionEffect.move(TransitionEdge.END))

高性能知识点

  • 动态加载数据场景可以使用LazyForEach遍历数据。
  • onAreaChange 在区域发生大小变化的时候会进行调用,由于删除操作或者网格元素的交互都能够触发区域函数的使用,操作频繁, 建议此处减少日志的打印、复用函数逻辑来降低性能的内耗。
  • onTouch 在进行手势操作的时候会进行多次调用,建议此处减少日志的打印、复用函数逻辑来降低性能的内耗。

工程结构&模块类型

复制代码
gridexchange                                 // har类型
|---model
|   |---AppInfo.ets                          // App信息
|   |---AttributeModifier.ets                // 属性对象
|   |---GridItemDeletionCtrl.ets             // 列表项交换
|   |---MockData.ets                         // 模拟数据
|---view
|   |---GridExchange.ets                     // 视图层-应用主页面

模块依赖

本实例依赖common模块来实现日志的打印、资源 的调用、依赖动态路由模块来实现页面的动态加载。

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)路线图、学习视频、文档用来跟着学习是非常有必要的。

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员

鸿蒙 NEXT 全栈开发学习笔记希望这一份鸿蒙学习文档能够给大家带来帮助~

这份鸿蒙(HarmonyOS NEXT)包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。


鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员: 想要拓展职业边界
零基础小白: 鸿蒙爱好者,希望从0到1学习,增加一项技能。
**技术提升/进阶跳槽:**发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频学习教程+学习PDF文档

HarmonyOS Next 最新全套视频教程

纯血版鸿蒙全套学习文档(面试、文档、全套视频等)

​​

《鸿蒙大厂面试真题》

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

相关推荐
腾讯TNTWeb前端团队1 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰5 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪5 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪5 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy6 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom6 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom6 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom7 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom7 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom7 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试