简介
本项目基于ArkUI中TS扩展的声明式开发范式,关于语法和概念直接看官网官方文档地址:
基于TS扩展的声明式开发范式1、基于TS扩展的声明式开发范式2
本文介绍列表滑动删除:
列表中只允许滑出其中一项
如果有打开的项,点击或滑动其他项都会关闭打开的项
点击删除,刷新列表界面
ArKUI系列文章
- 【HarmonyOS ArkUI之仿微信朋友圈图片预览】
- 【HarmonyOS ArkUI之仿微信图片选择】
- 【HarmonyOS ArkUI之自定义组件侧滑菜单(JS)】
- 【HarmonyOS ArkUI之聊天列表滑动删除(TS)】
效果演示
主要知识点
可滑动的容器组件(Scroll)、触摸事件(onTouch)
实现思路
我把界面精简了一下,减少代码量,帮助更好的理解主要逻辑。
1、item布局
主要使用scroll包裹内容,scroll设置为横向滑动(部分代码)
- .....
- Scroll() {
- Row() {
- Text('内容数据')
- .width('100%').height(65)
-
- Button() {
- Text('删除')
- }
- .width(100).height(65)
- }
- }.scrollable(ScrollDirection.Horizontal) // 设置为横向滑动
- .....
2、Scroll容器
给Scroll容器绑定滑动组件的控制器,只用到其中的一个方法:滑动到指定位置 scrollTo
- scrollTo(
- value: {
- xOffset: number | string, yOffset: number | string, animation?
- : { duration: number, curve: Curve }
- }
- );
看源码得知可以设置动画时间,注意:时间目前好像不能设置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 } })
- })
- .....
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
- }
- })
- .....
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
= [ - { 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%')
- }
- }
结尾
因为ArkUI声明式开发,是鸿蒙新出的东西,API还不是那么完善,后续跟进官网更新。以下是需要优化点:
ArkUI中的TS没有JS中的新出的插槽概念,要不然直接封装成组件,提供两个对外的接口,一个传入内容布局、一个操作布局,就像Android的组件库一样,使用者不需要知道内部实现。
每天进步一点点、需要付出努力亿点点。