HarmonyOS ArkUI之聊天列表滑动删除(TS)

开发 前端 OpenHarmony
本项目基于ArkUI中TS扩展的声明式开发范式,本文介绍列表滑动删除:列表中只允许滑出其中一项,如果有打开的项,点击或滑动其他项都会关闭打开的项,点击删除,刷新列表界面。

[[436946]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

简介

本项目基于ArkUI中TS扩展的声明式开发范式,关于语法和概念直接看官网官方文档地址:

基于TS扩展的声明式开发范式1基于TS扩展的声明式开发范式2

本文介绍列表滑动删除:

列表中只允许滑出其中一项

如果有打开的项,点击或滑动其他项都会关闭打开的项

点击删除,刷新列表界面

ArKUI系列文章

效果演示

HarmonyOS ArkUI之聊天列表滑动删除(TS)-鸿蒙HarmonyOS技术社区

主要知识点

可滑动的容器组件(Scroll)、触摸事件(onTouch)

实现思路

我把界面精简了一下,减少代码量,帮助更好的理解主要逻辑。

HarmonyOS ArkUI之聊天列表滑动删除(TS)-鸿蒙HarmonyOS技术社区

1、item布局

主要使用scroll包裹内容,scroll设置为横向滑动(部分代码)

..... 
Scroll() { 
      Row() { 
        Text('内容数据'
          .width('100%').height(65) 
 
        Button() { 
          Text('删除'
        } 
        .width(100).height(65) 
      } 
 }.scrollable(ScrollDirection.Horizontal) // 设置为横向滑动 
..... 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

2、Scroll容器

给Scroll容器绑定滑动组件的控制器,只用到其中的一个方法:滑动到指定位置 scrollTo

scrollTo( 
    value: { 
    xOffset: number | string, yOffset: number | string, animation? 
        : { duration: number, curve: Curve } 
    } 
); 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

看源码得知可以设置动画时间,注意:时间目前好像不能设置300毫秒以上,往下设置可以 (部分代码)

..... 
// 初始化控制器 
private scroller= new Scroller() 
Scroll(scroller) { // 控制器绑定到滑动容器中 
      Row() { 
        Text('内容数据'
          .width('100%').height(65) 
 
        Button() { 
          Text('删除'
        } 
        .width(100).height(65) 
      } 
 }.scrollable(ScrollDirection.Horizontal) 
 
Button() { 
  Text('点击回到原位')            
}.onClick(()=>{ 
  scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 200, curve: Curve.Linear } }) 
}) 
..... 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

3、设置触摸事件

根据移动的偏移量,判断大于删除布局宽度的一半则:打开删除布局(部分代码)

..... 
// 初始化控制器 
private scroller= new Scroller() 
// 按下的x轴坐标 
private downX = 0 
// 删除按钮的宽度 
private deleteWidth = 100 
 
Scroll(scroller) { // 控制器绑定到滑动容器中 
      Row() { 
        Text('内容数据'
          .width('100%').height(65) 
 
        Button() { 
          Text('删除'
        } 
        .width(this.deleteWidth).height(65) 
      } 
 }.scrollable(ScrollDirection.Horizontal) 
.onTouch((event: TouchEvent) => { // 触摸事件 
      // 根据触摸类型判断 
      switch (event.type) { 
        case TouchType.Down: // 触摸按下 
          // 记录按下的x轴坐标 
          this.downX = event.touches[0].x 
          break 
        case TouchType.Up: // 触摸抬起 
          // 触摸抬起,根据x轴总偏移量,判断是否打开删除 
          let xOffset = event.touches[0].x - this.downX 
          // 滑到目标x轴的位置 
          var toxOffset = 0           
          // 偏移量超过删除按钮一半且左滑,设置打开 
          if (Math.abs(xOffset) > vp2px(this.deleteWidth) / 2 && xOffset < 0) { 
              // 删除布局宽度 
              toxOffset = vp2px(this.deleteWidth) 
          } 
          // 滑动指定位置,设置动画 
          item.scroller.scrollTo({ xOffset: toxOffset, yOffset: 0, 
            animation: { duration: 300, curve: Curve.Linear } }) 
          // 重置按下的x轴坐标 
          this.downX = 0 
          break 
      } 
    }) 
..... 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.

4、使用列表加载

需要主要的点:

  • 需要给每个item绑定控制器,这样才能控制对应的item打开或关闭
  • 打开的item记录一下数据,点击内容或删除、滑动其他item:如果有带打开的item,进行关闭

以下是完整代码,可直接粘贴运行使用。

class TestData { 
  content: string 
  scroller: Scroller 
 
  constructor(content: string, scroller: Scroller) { 
    this.content = content 
    this.scroller = scroller 
  } 

 
@Entry 
@Component 
struct SlidingDeleteList { 
  // 删除按钮的宽度 
  private deleteWidth = 100 
  // 按下的x轴坐标 
  private downX = 0 
  // 已经打开删除的数据 
  private openDeleteData: TestData = null 
  // 测试数据 
  @State private listData: Array<TestData> = [ 
    { content: '内容数据1', scroller: new Scroller() }, { content: '内容数据2', scroller: new Scroller() }, 
    { content: '内容数据3', scroller: new Scroller() }, { content: '内容数据4', scroller: new Scroller() }, 
    { content: '内容数据5', scroller: new Scroller() }, { content: '内容数据6', scroller: new Scroller() }, 
    { content: '内容数据7', scroller: new Scroller() }, { content: '内容数据8', scroller: new Scroller() }, 
  ] 
 
  @Builder CustomItem(item:TestData) { 
    Scroll(item.scroller) { 
      Row() { 
        Text(item.content) 
          .width('100%').height(65) 
          .fontSize(16).textAlign(TextAlign.Center) 
          .onClick(() => { 
            // 如果删除按钮打开,关闭删除按钮且返回 
            if (this.openDeleteData != null) { 
              this.openDeleteData.scroller.scrollTo({ xOffset: 0, yOffset: 0, 
                animation: { duration: 100, curve: Curve.Linear } }) 
              this.openDeleteData = null 
              return 
            } 
            console.log('========点击内容========='
          }) 
 
        Button() { 
          Text('删除'
            .fontSize(15) 
            .fontColor(Color.White) 
        } 
        .type(ButtonType.Normal) 
        .width(this.deleteWidth).height(65) 
        .backgroundColor(Color.Red) 
        .onClick(() => { 
          // 删除当前数据 
          this.listData.splice(this.listData.indexOf(item), 1) 
 
          // 关闭删除按钮 
          if (this.openDeleteData != null) { 
            this.openDeleteData.scroller.scrollTo({ xOffset: 0, yOffset: 0, 
              animation: { duration: 100, curve: Curve.Linear } }) 
            this.openDeleteData = null 
          } 
          console.log('========点击删除========='
        }) 
      } 
    }.scrollable(ScrollDirection.Horizontal) 
    .onTouch((event: TouchEvent) => { // 触摸事件 
      // 判断是否有打开删除组件,有则关闭 
      if (this.openDeleteData != null && this.openDeleteData != item) { 
        this.openDeleteData.scroller.scrollTo({ xOffset: 0, yOffset: 0, 
          animation: { duration: 100, curve: Curve.Linear } }) 
      } 
 
      // 根据触摸类型判断 
      switch (event.type) { 
        case TouchType.Down: // 触摸按下 
          // 记录按下的x轴坐标 
          this.downX = event.touches[0].x 
          break 
        case TouchType.Up: // 触摸抬起 
          // 触摸抬起,根据x轴总偏移量,判断是否打开删除 
          let xOffset = event.touches[0].x - this.downX 
          // 防止消费点击事件 
          if (xOffset == 0) { 
            return 
          } 
          // 滑到x轴的位置 
          var toxOffset = 0 
          // 开启删除的对象置为null 
          this.openDeleteData = null
          // 偏移量超过删除按钮一半且左滑,设置打开 
          if (Math.abs(xOffset) > vp2px(this.deleteWidth) / 2 && xOffset < 0) { 
            // 删除布局宽度 
            toxOffset = vp2px(this.deleteWidth) 
            this.openDeleteData = item 
          } 
          // 滑动指定位置,设置动画 
          item.scroller.scrollTo({ xOffset: toxOffset, yOffset: 0, 
            animation: { duration: 300, curve: Curve.Linear } }) 
          // 重置按下的x轴坐标 
          this.downX = 0 
          break 
      } 
    }) 
  } 
 
  build() { 
    Column() { 
      List() { 
        ForEach(this.listData, item => { 
          ListItem() { 
            this.CustomItem(item) 
          } 
        }, item => item.toString()) 
      }.divider({ color: '#f1efef', strokeWidth: 1 }) 
    } 
    .width('100%'
    .height('100%'
  } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.

结尾

因为ArkUI声明式开发,是鸿蒙新出的东西,API还不是那么完善,后续跟进官网更新。以下是需要优化点:

ArkUI中的TS没有JS中的新出的插槽概念,要不然直接封装成组件,提供两个对外的接口,一个传入内容布局、一个操作布局,就像Android的组件库一样,使用者不需要知道内部实现。

每天进步一点点、需要付出努力亿点点。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2021-12-01 10:02:57

鸿蒙HarmonyOS应用

2022-08-23 16:07:02

ArkUI鸿蒙

2022-04-08 14:47:11

ArkUI列表字母索引鸿蒙

2022-09-26 15:16:03

ArkUITS

2022-08-08 19:46:26

ArkUI鸿蒙

2022-07-20 15:32:25

时钟翻页Text组件

2014-12-31 14:52:27

SwipeMenuLiSwipeMenu

2022-08-24 16:08:22

ETS鸿蒙

2022-09-02 15:17:04

ArkUI鸿蒙

2021-12-03 09:49:59

鸿蒙HarmonyOS应用

2021-11-23 10:00:55

鸿蒙HarmonyOS应用

2022-11-21 16:15:41

ArkUI鸿蒙

2021-01-08 09:55:17

鸿蒙HarmonyOS组装列表

2022-07-28 14:26:11

AI作诗应用开发

2021-11-16 09:38:10

鸿蒙HarmonyOS应用

2023-08-24 16:42:29

Sample聊天实例应用

2022-05-20 14:34:20

list组件鸿蒙操作系统

2021-11-19 09:48:33

鸿蒙HarmonyOS应用

2017-03-13 10:11:28

AndroidRecyclerVie功能介绍

2020-10-30 20:54:29

微信新功能移动应用
点赞
收藏

51CTO技术栈公众号