HarmonyOS NEXT应用开发之左右拖动切换图片效果案例

介绍

本示例使用滑动手势监听,实时调整左右两侧内容显示区域大小和效果。通过绑定gesture事件中的PanGesture平移手势,实时获取拖动距离。当拖动时,实时地调节左右两个Image组件的宽度,从而成功实现左右拖动切换图片效果的功能。

效果图预览

使用说明

  1. 点击中间按钮进行左右拖动切换图片。

实现思路

本例涉及的关键特性和实现方案如下:

  1. 创建三个Stack组件,用来展示装修前后对比图,第一个和第三个Stack分别存放装修前的图片和装修后的图片,zIndex设置为1。第二个Stack存放按钮的图片,zIndex设置为2,这样按钮的图片就会覆盖在两张装修图片之上。 源码参考DragToSwitchPicturesView.ets

    Row() {
    Stack() {...}
    .zIndex(CONFIGURATION.ZINDEX1)
    .width(this.leftImageWidth) // z序设为1,为了使按钮图片浮在装修图片上。

    Stack() {...}
    .width($r('app.integer.drag_button_stack_width'))
    .zIndex(CONFIGURATION.ZINDEX2) // z序设为2,为了使按钮图片浮在装修图片上。

    Stack() {...}
    .zIndex(CONFIGURATION.ZINDEX1) // z序设为1,为了使按钮图片浮在装修图片上。
    .width(this.rightImageWidth)
    }
    .justifyContent(FlexAlign.Center)
    .width($r('app.string.full_size'))

  2. 将Image组件放在Row容器里,将Row容器的宽度设置为状态变量,再利用clip属性对于Row容器进行裁剪。 源码参考DragToSwitchPicturesView.ets

    Row() {
    Image(r('app.media.before_decoration')) .width(r('app.integer.decoration_width'))// Image的width固定,Row的宽度变化,通过裁剪实现布局效果。
    .height($r('app.integer.decoration_height'))
    .draggable(false) // 设置Image不能拖动,不然长按Image会被拖动。
    }
    .width(this.leftImageWidth) // 将左侧Row的width设置为leftImageWidth,这样左侧Row的width随leftImageWidth的变化而变化。
    .clip(true) // clip属性设置为true,裁剪超出Row宽度的图片。
    .zIndex(CONFIGURATION.ZINDEX1) // z序设为1,为了使水印浮在装修图片上。
    .borderRadius({
    topLeft: $r('app.integer.borderradius'),
    bottomLeft: $r('app.integer.borderradius')
    }) // 将Row的左上角和左下角弧度设为10实现效果。

  3. 右边的Image组件与左边同样的操作,但是新增了一个direction属性,使元素从右至左进行布局,为的是让Row从左侧开始裁剪。 源码参考DragToSwitchPicturesView.ets

    Row() {
    Image(r('app.media.after_decoration')) .width(r('app.integer.decoration_width'))
    .height($r('app.integer.decoration_height'))
    .draggable(false)
    }
    .width(this.rightImageWidth)
    .clip(true)
    .zIndex(CONFIGURATION.ZINDEX1) // z序设为1,为了使水印浮在装修图片上。
    // TODO: 知识点:左边Row使用clip时从右边开始裁剪,加了Direction.Rtl后,元素从右到左布局,右边Row使用clip时从左边开始裁剪,这是实现滑动改变视图内容大小的关键。
    .direction(Direction.Rtl)
    .borderRadius({
    topRight: $r('app.integer.borderradius'),
    bottomRight: $r('app.integer.borderradius')
    }) // 将Row的右上角和右下角弧度设为10实现效果。

  4. 中间的Image组件通过手势事件中的滑动手势对Image组件滑动进行监听,对左右Image组件的宽度进行计算从而重新布局渲染。 源码参考DragToSwitchPicturesView.ets

    Image(r('app.media.drag_button')) .width(r('app.integer.drag_button_image_width'))
    .height($r('app.integer.decoration_height'))
    .draggable(false)
    .gesture( // TODO: 知识点:拖动手势事件设置一个手指,滑动的最小距离设置为1vp,实现滑动时按钮跟手动效。
    PanGesture({ fingers: CONFIGURATION.PANGESTURE_FINGERS, distance: CONFIGURATION.PANGESTURE_DISTANCE })
    .onActionStart(() => {
    this.dragRefOffset = CONFIGURATION.INIT_VALUE; // 每次拖动开始时将图标拖动的距离初始化。
    })
    // TODO: 性能知识点: 该函数是系统高频回调函数,避免在函数中进行冗余或耗时操作,例如应该减少或避免在函数打印日志,会有较大的性能损耗。
    .onActionUpdate((event: GestureEvent) => {
    // 通过监听GestureEvent事件,实时监听图标拖动距离
    this.dragRefOffset = event.offsetX;
    this.leftImageWidth = this.imageWidth + this.dragRefOffset;
    this.rightImageWidth = CONFIGURATION.IMAGE_FULL_SIZE - this.leftImageWidth;
    if (this.leftImageWidth >= CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE) { // 当leftImageWidth大于等于310vp时,设置左右Image为固定值,实现停止滑动效果。
    this.leftImageWidth = CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE;
    this.rightImageWidth = CONFIGURATION.RIGHT_IMAGE_RIGHT_LIMIT_SIZE;
    } else if (this.leftImageWidth <= CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE) { // 当leftImageWidth小于等于30vp时,设置左右Image为固定值,实现停止滑动效果。
    this.leftImageWidth = CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE;
    this.rightImageWidth = CONFIGURATION.RIGHT_IMAGE_LEFT_LIMIT_SIZE;
    }
    })
    .onActionEnd((event: GestureEvent) => {
    if (this.leftImageWidth <= CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE) {
    this.leftImageWidth = CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE;
    this.rightImageWidth = CONFIGURATION.RIGHT_IMAGE_LEFT_LIMIT_SIZE;
    this.imageWidth = CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE;
    } else if (this.leftImageWidth >= CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE) {
    this.leftImageWidth = CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE;
    this.rightImageWidth = CONFIGURATION.RIGHT_IMAGE_RIGHT_LIMIT_SIZE;
    this.imageWidth = CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE;
    } else {
    this.leftImageWidth = this.imageWidth + this.dragRefOffset; // 滑动结束时leftImageWidth等于左边原有Width+拖动距离。
    this.rightImageWidth = CONFIGURATION.IMAGE_FULL_SIZE - this.leftImageWidth; // 滑动结束时rightImageWidth等于340-leftImageWidth。
    this.imageWidth = this.leftImageWidth; // 滑动结束时ImageWidth等于leftImageWidth。
    }
    })
    )

工程结构&模块类型

   dragtoswitchpictures                             // har包
   |---common
   |   |---Constants.ets                            // 常量类
   |---data
   |   |---DragToSwitchPicturesData.ets             // 生成模拟数据
   |---datasource
   |   |---BasicDataSource.ets                      // Basic数据控制器
   |   |---DragToSwitchPicturesDataSource.ets       // 左右拖动切换图片数据控制器
   |---mainpage
   |   |---DragToSwitchPictures.ets                 // 主页面
   |---model
   |   |---DragToSwitchPicturesModule.ets           // 左右拖动切换图片数据模型
   |---view
   |   |---DragToSwitchPicturesView.ets             // 左右拖动切换图片视图
   |   |---DesignCattleView.ets                     // AI设计视图
   |   |---TabsWaterFlowView.ets                    // 瀑布流嵌套Tabs视图

模块依赖

routermodule

高性能知识点

本例使用了onActionUpdate函数。该函数是系统高频回调函数,避免在函数中进行冗余或耗时操作,例如应该减少或避免在函数打印日志,会有较大的性能损耗。

本示例使用了LazyForEach进行数据懒加载,WaterFlow布局时会根据可视区域按需创建FlowItem组件,并在FlowItem滑出可视区域外时销毁以降低内存占用。

本示例使用了cachedCount设置预加载的FlowItem的数量,只在LazyForEach中生效,设置该属性后会缓存cachedCount个FlowItem,LazyForEach超出显示和缓存范围的FlowItem会被释放。

参考资料

LazyForEach:数据懒加载

Tabs

WaterFlow

ZIndex

PanGesture

clip

direction

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ......

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ......

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ......

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题

2.性能优化方向

3.架构方向

4.鸿蒙开发系统底层方向

5.鸿蒙音视频开发方向

6.鸿蒙车载开发方向

7.鸿蒙南向开发方向

腾讯T10级高工技术,安卓全套VIP课程全网免费送:https://qr21.cn/D2k9D5

相关推荐
长弓三石1 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
SameX3 小时前
鸿蒙 Next 电商应用安全支付与密码保护实践
前端·harmonyos
SuperHeroWu74 小时前
【HarmonyOS】键盘遮挡输入框UI布局处理
华为·harmonyos·压缩·keyboard·键盘遮挡·抬起
努力变厉害的小超超8 小时前
ArkTS中的组件基础、状态管理、样式处理、class语法以及界面渲染
笔记·鸿蒙
sanzk8 小时前
华为鸿蒙应用开发
华为·harmonyos
SoraLuna13 小时前
「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现
macos·ui·harmonyos
ClkLog-开源埋点用户分析14 小时前
ClkLog企业版(CDP)预售开启,更有鸿蒙SDK前来助力
华为·开源·开源软件·harmonyos
mg66814 小时前
鸿蒙系统的优势 开发 环境搭建 开发小示例
华为·harmonyos
模拟IC攻城狮14 小时前
华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目——共8套(每套四十题)
嵌入式硬件·华为·硬件架构·芯片
lqj_本人14 小时前
鸿蒙next选择 Flutter 开发跨平台应用的原因
flutter·华为·harmonyos