【共创季稿事节】鸿蒙原生 ArkTS 布局实战:List 滑动删除(SwipeToDelete)完全指南
鸿蒙原生 ArkTS 布局实战:List 滑动删除(SwipeToDelete)完全指南



一、引言
在移动应用开发中,滑动操作(Swipe Action)已经成为用户最熟悉的交互手势之一。无论是 iOS 的 Mail 应用中滑动标记已读,还是微信中滑动删除聊天记录,滑动操作为用户提供了一种快捷、直观、高效的交互方式,避免了长按菜单或进入编辑模式的繁琐步骤。
HarmonyOS NEXT 作为华为全场景智能生态的操作系统,在其原生声明式 UI 框架 ArkTS 中,提供了极其优雅的滑动操作 API——.swipeAction()。通过这个 API,开发者可以轻松地为 List 列表项添加左右滑动面板,实现删除、收藏、标记等常见操作。
本篇文章将从一个完整的实战项目出发,带你从零掌握 ArkTS 中 List 滑动删除的完整实现。全文将涵盖:
- ArkTS 项目结构与页面路由
- List 组件的基础使用
.swipeAction()API 的详细参数解析@Builder与@Component在滑动面板中的正确用法- ArkTS 数据模型与状态管理的注意事项
- 常见编译错误与解决方案
- 从 API 23 升级到 API 24 的适配要点
二、项目背景与环境配置
2.1 开发环境要求
在开始之前,请确保你的开发环境满足以下条件:
| 环境项 | 要求 |
|---|---|
| 操作系统 | Windows 10/11 或 macOS |
| 开发工具 | DevEco Studio 5.0+ |
| SDK 版本 | HarmonyOS SDK API 24(7.0.0) |
| 语言版本 | ArkTS(基于 TypeScript 5.0+) |
| 目标设备 | HarmonyOS NEXT 模拟器或真机 |
2.2 API 版本升级说明(23 → 24)
本项目的初始模板使用的是 API 23(SDK 6.1.0),但本文所有代码均已适配 API 24(SDK 7.0.0)。升级到 API 24 后,主要变化包括:
- 编译规则更严格:对类型检查、空安全等有更细粒度的管控
- 废弃 API 标记:部分 API(如
promptAction.showToast)标记为 deprecated,推荐迁移到新的@ohos.arkui.dialog模块 - 性能优化:List 组件的懒加载和复用机制有底层改进
在 build-profile.json5 中确认 SDK 版本配置:
{
"app": {
"products": [
{
"name": "default",
"targetSdkVersion": "7.0.0(24)",
"compatibleSdkVersion": "7.0.0(24)",
"runtimeOS": "HarmonyOS"
}
]
}
}
2.3 项目结构概览
一个标准的 HarmonyOS NEXT 工程结构如下:
ap06/
├── AppScope/ # 应用全局配置
│ └── app.json5 # 应用名称、图标等元信息
├── entry/ # 模块目录
│ ├── src/main/
│ │ ├── ets/
│ │ │ ├── entryability/ # Ability 生命周期
│ │ │ │ └── EntryAbility.ets # 应用入口,负责加载页面
│ │ │ └── pages/
│ │ │ ├── Index.ets # 默认页面(Hello World)
│ │ │ └── SwipeToDeleteDemo.ets # 我们的滑动删除页面
│ │ └── resources/ # 资源文件
│ └── build-profile.json5 # 模块构建配置
├── build-profile.json5 # 项目级构建配置
└── oh-package.json5 # 包管理配置
2.4 页面路由注册
在 HarmonyOS NEXT 中,所有页面都需要在 main_pages.json 中注册。我们添加了新页面后,需要编辑 entry/src/main/resources/base/profile/main_pages.json:
{
"src": [
"pages/Index",
"pages/SwipeToDeleteDemo"
]
}
然后修改 EntryAbility.ets 中的启动页面:
// 将默认的 pages/Index 改为我们的新页面
windowStage.loadContent('pages/SwipeToDeleteDemo', (err) => {
if (err.code) {
hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
return;
}
hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
});
三、核心技术:List + .swipeAction()
3.1 List 组件概述
List 是 ArkTS 提供的高性能列表容器,它支持:
- 懒加载:只渲染可视区域内的列表项,大量数据时依然流畅
- 复用机制:离屏的 ListItem 会被回收复用,减少内存开销
- 方向控制:支持垂直(默认)和水平两种滚动方向
- 粘性标题:支持分组列表的粘性标题(sticky header)
- 滑动操作:通过
.swipeAction()为每一项添加滑动面板
基本用法:
List() {
ForEach(this.dataArray, (item: DataType) => {
ListItem() {
// 你的列表项内容
Text(item.title)
}
}, (item: DataType) => item.id.toString())
}
.width('100%')
.height('100%')
3.2 .swipeAction() API 深度解析
.swipeAction() 是 ListItem 组件的方法,用于为列表项添加滑动操作面板。它的完整签名如下:
ListItem()
.swipeAction(value: SwipeActionOptions)
其中 SwipeActionOptions 接口的定义为:
interface SwipeActionOptions {
start?: SwipeActionItem; // 起始侧面板(LTR 布局中为左侧/向右滑)
end?: SwipeActionItem; // 结束侧面板(LTR 布局中为右侧/向左滑)
edgeEffect?: SwipeEdgeEffect; // 滑动到边缘的弹性效果
}
interface SwipeActionItem {
builder: CustomBuilder; // 面板的 UI 构建函数(必须为 @Builder)
onAction?: () => void; // 面板被触发时的回调
offset?: number; // 面板偏移量
}
参数详解
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
start |
SwipeActionItem |
否 | 用户向右滑动时,从左侧露出的操作面板。常用于"删除"、"置顶"等操作 |
end |
SwipeActionItem |
否 | 用户向左滑动时,从右侧露出的操作面板。常用于"收藏"、"更多"等操作 |
edgeEffect |
SwipeEdgeEffect |
否 | 滑动到边缘时的效果:Spring(弹簧回弹)或 None(无效果) |
builder |
CustomBuilder |
是 | 面板内容的构建器,必须使用 @Builder 装饰的函数 |
onAction |
() => void |
否 | 滑动面板被触发时的回调函数 |
关于 CustomBuilder 的重要约束
这是 ArkTS 初学者最容易踩的坑。 .swipeAction() 的 builder 属性类型为 CustomBuilder,它不接受 @Component 结构体,只能接受用 @Builder 装饰的函数。
错误写法(❌ 编译报错)
.swipeAction({ start: { builder: DeleteButton() // ❌ DeleteButton 是 @Component,不能赋值给 CustomBuilder } })
正确写法(✅ 正常工作)
@Builder deleteButtonBuilder(item: NotificationItem) { Button('删除') .onClick(() => { this.deleteItem(item); }) } // 在 ListItem 中: .swipeAction({ start: { builder: (): void => this.deleteButtonBuilder(item) } })
这里还有一个细节:builder 需要用箭头函数包裹 @Builder 的调用,即 (): void => this.deleteButtonBuilder(item),而不是直接传递 this.deleteButtonBuilder(item)。这是因为 CustomBuilder 需要延迟执行,在滑动触发时才构建 UI。
3.3 SwipeEdgeEffect 弹性效果
edgeEffect: SwipeEdgeEffect.Spring // 推荐
SwipeEdgeEffect.Spring 提供了类似 iOS 的弹簧回弹效果:当用户滑动面板超出边界时,面板会像弹簧一样回弹,带来更自然的物理手感。如果设置为 SwipeEdgeEffect.None,则滑动到边界会直接停止,显得生硬。
四、数据模型设计(ArkTS 注意事项)
4.1 类的定义
在 ArkTS 中定义数据模型时,有一个重要的语法限制:不能在构造函数的参数中直接声明并赋值字段。
// ❌ 错误写法:arkts-no-ctor-prop-decls
class NotificationItem {
constructor(public id: number, public title: string, public content: string) {
}
}
// ✅ 正确写法:先声明字段,再在构造函数中赋值
class NotificationItem {
id: number = 0; // 必须提供默认值
title: string = '';
content: string = '';
constructor(id: number, title: string, content: string) {
this.id = id; // 在构造函数体中进行赋值
this.title = title;
this.content = content;
}
}
4.2 @State 装饰器与响应式数据
@State 是 ArkTS 中最核心的装饰器之一。被 @State 修饰的变量,当其值发生变化时,框架会自动重新渲染与之绑定的 UI。
@State private notifications: NotificationItem[] = [
new NotificationItem(1, '系统更新提醒', '您的系统已更新至 HarmonyOS NEXT 5.0...'),
// ...更多数据
];
当你调用 this.notifications.splice(index, 1) 删除一项后,@State 会检测到数组变化,List 会自动移除对应的列表项并更新界面。无需手动刷新,这是声明式 UI 的核心优势。
五、实战代码解析
下面我们逐段解析 SwipeToDeleteDemo.ets 的核心代码。
5.1 页面入口与布局结构
@Entry
@Component
struct SwipeToDeleteDemo {
@State private notifications: NotificationItem[] = [ /* 6条数据 */ ];
build() {
Column() {
TitleBar({ title: 'List 滑动删除演示' }); // 顶部标题栏
TipBanner(); // 操作提示横幅
List() { /* 列表内容 */ } // 核心列表
BottomActionBar({ onReset: () => this.resetList() }) // 底部重置按钮
}
}
}
整个页面采用从上到下的 Column 布局,分为四个区域:
- TitleBar:蓝色的标题栏,显示页面名称
- TipBanner:橙色的操作提示条,告诉用户滑动手势的方向
- List:占据剩余空间的核心列表区域
- BottomActionBar:底部的重置按钮
5.2 列表与滑动操作的绑定
这是整个应用的核心代码:
List() {
ForEach(this.notifications, (item: NotificationItem) => {
ListItem() {
NotificationCard({ item: item })
}
.height(80)
.swipeAction({ // ← 核心:绑定滑动操作
start: { // 向右滑动 → 左侧露出删除
builder: (): void => this.deleteButtonBuilder(item)
},
end: { // 向左滑动 → 右侧露出收藏
builder: (): void => this.favoriteButtonBuilder(item)
},
edgeEffect: SwipeEdgeEffect.Spring // 弹性回弹效果
})
}, (item: NotificationItem) => item.id.toString()) // key 生成器
}
关键细节:
- 每个
ListItem独立绑定.swipeAction(),互不干扰 ForEach的第三个参数是 key 生成器,使用item.id.toString()确保列表项的唯一标识。当列表数据变化时,框架通过 key 来识别哪些项需要增、删、移,而不是全部重新渲染。这是高性能列表的关键height(80)统一设置每个列表项的高度为 80vp
5.3 @Builder 构建滑动面板
@Builder
deleteButtonBuilder(item: NotificationItem) {
Button('删除')
.width(80)
.height('100%')
.backgroundColor('#FF3B30') // iOS 风格的红色
.fontColor(Color.White)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.borderRadius(0) // 直角,与列表项融为一体
.onClick(() => {
this.deleteItem(item); // 点击执行删除
});
}
@Builder
favoriteButtonBuilder(item: NotificationItem) {
Button('收藏')
.width(80)
.height('100%')
.backgroundColor('#007AFF') // 蓝色
.fontColor(Color.White)
.fontSize(16)
.borderRadius(0)
.onClick(() => {
this.favoriteItem(item); // 点击执行收藏
});
}
设计要点:
- 按钮的
.width(80)决定了滑动面板的宽度。你可以根据实际需求调整 .height('100%')让按钮撑满整个 ListItem 的高度.borderRadius(0)使用直角,让按钮与列表项边界完全贴合,视觉上更干净@Builder函数可以接受参数(item: NotificationItem),将当前列表项的数据传入
5.4 删除与状态更新
private deleteItem(item: NotificationItem): void {
let index = this.notifications.findIndex(n => n.id === item.id);
if (index !== -1) {
this.notifications.splice(index, 1); // 从响应式数组中移除
promptAction.showToast({
message: `已删除:「${item.title}」`,
duration: 1500
});
}
}
删除的流程非常简洁:
- 通过
findIndex找到要删除项在数组中的索引 - 调用
splice(index, 1)从数组中移除一项 - @State 检测到数组变化,自动触发 UI 更新
- showToast 给用户一个操作反馈提示
5.5 重置列表
private resetList(): void {
this.notifications = [
new NotificationItem(1, '系统更新提醒', '您的系统已更新至 HarmonyOS NEXT 5.0...'),
// ... 重新初始化为全部 6 条数据
];
}
resetList() 将 notifications 数组重新赋值为初始数据。注意:这里直接赋值一个新数组,而不是修改原数组。@State 装饰器会检测到引用变化(数组地址改变),从而触发全量刷新。如果只想修改数组内容而不改变引用,则需要用 splice、push 等变异方法。
六、子组件设计与复用
将一个大型页面拆分为多个小的 @Component,是 ArkTS 推荐的最佳实践。本示例将页面拆分为 4 个子组件:
6.1 TitleBar(标题栏)
@Component
struct TitleBar {
private title: string = '';
build() {
Row() {
Text(this.title)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
}
.width('100%')
.height(56)
.backgroundColor('#0A59F7') // 鸿蒙品牌蓝色
.padding({ left: 20, right: 20 })
}
}
6.2 TipBanner(操作提示条)
@Component
struct TipBanner {
build() {
Row() {
Text('👉 向右滑动列表项 → 删除 | 👈 向左滑动 → 收藏')
.fontSize(13)
.fontColor('#666666')
.textAlign(TextAlign.Center)
}
.width('100%')
.padding({ top: 12, bottom: 12 })
.backgroundColor('#FFEEDD')
}
}
这个提示条虽然简单,但对用户体验至关重要——用户需要被引导才知道列表项是可以滑动的。这也是移动端设计中的一个重要原则:可见性(Discoverability)。
6.3 NotificationCard(通知卡片)
@Component
struct NotificationCard {
private item: NotificationItem = new NotificationItem(0, '', '');
build() {
Row() {
// 左侧圆形图标(首字头像)
Circle()
.width(40).height(40)
.fill('#0A59F7').opacity(0.85)
.margin({ right: 14 })
.overlay(this.iconBuilder(this.item.title.charAt(0)))
// 右侧文字区域
Column() {
Text(this.item.title)
.fontSize(16).fontWeight(FontWeight.Medium)
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
Text(this.item.content)
.fontSize(13).fontColor('#999999')
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
}
.padding({ left: 16, right: 16 })
.backgroundColor(Color.White)
.alignItems(VerticalAlign.Center)
}
@Builder
iconBuilder(char: string) {
Text(char)
.fontColor(Color.White).fontSize(18).fontWeight(FontWeight.Bold)
}
}
注意:Circle() 的 .overlay() 方法同样接收 CustomBuilder 类型,因此也需要用 @Builder 函数构建内部的 Text。
6.4 BottomActionBar(底部操作栏)
@Component
struct BottomActionBar {
private onReset?: () => void;
build() {
Row() {
Button('🔄 重置列表')
.width(160).height(40)
.backgroundColor('#0A59F7')
.fontColor(Color.White).fontSize(15)
.borderRadius(20)
.onClick(() => { this.onReset?.(); })
}
.width('100%')
.height(64)
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.White)
.shadow({ radius: 4, color: '#20000000' })
}
}
子组件通信方式:BottomActionBar 通过 private onReset?: () => void 定义回调函数属性,父组件在创建时传入 onReset: () => this.resetList()。这是 ArkTS 中父子组件通信的标准模式。
七、完整代码清单
以下是 SwipeToDeleteDemo.ets 的完整代码(约 307 行):
/*
* 滑动删除(SwipeToDelete)示例页面
* ================================
* 布局要点:
* 1. List + .swipeAction() 实现列表项滑动操作
* 2. start 参数:向右滑动时在左侧展示的操作面板(删除按钮)
* 3. end 参数:向左滑动时在右侧展示的操作面板(收藏按钮)
* 4. 通过 @State 驱动数据变化,删除后自动刷新 UI
* 5. 使用 @Builder 自定义构建滑动操作面板(ArkTS 要求 CustomBuilder 类型)
*/
import { promptAction } from '@kit.ArkUI';
// ----- 数据模型 -----
class NotificationItem {
id: number = 0;
title: string = '';
content: string = '';
constructor(id: number, title: string, content: string) {
this.id = id;
this.title = title;
this.content = content;
}
}
// ----- 主页面 -----
@Entry
@Component
struct SwipeToDeleteDemo {
@State private notifications: NotificationItem[] = [
new NotificationItem(1, '系统更新提醒', '您的系统已更新至 HarmonyOS NEXT 5.0,点击查看详情。'),
new NotificationItem(2, '新消息通知', '张三 回复了您的评论:"感谢分享!"'),
new NotificationItem(3, '应用下载完成', '《备忘录》应用已下载完成,点击安装。'),
new NotificationItem(4, '安全提醒', '检测到异地登录,建议立即修改密码。'),
new NotificationItem(5, '日历提醒', '您有一个会议将于 15:00 开始,请准时参加。'),
new NotificationItem(6, '订阅更新', '您关注的专栏「鸿蒙开发实战」发布了新文章。'),
];
build() {
Column() {
TitleBar({ title: 'List 滑动删除演示' })
TipBanner()
List() {
ForEach(this.notifications, (item: NotificationItem) => {
ListItem() {
NotificationCard({ item: item })
}
.height(80)
.swipeAction({
start: {
builder: (): void => this.deleteButtonBuilder(item)
},
end: {
builder: (): void => this.favoriteButtonBuilder(item)
},
edgeEffect: SwipeEdgeEffect.Spring
})
}, (item: NotificationItem) => item.id.toString())
}
.width('100%')
.layoutWeight(1)
.backgroundColor(Color.Transparent)
BottomActionBar({ onReset: () => this.resetList() })
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
@Builder
deleteButtonBuilder(item: NotificationItem) {
Button('删除')
.width(80).height('100%')
.backgroundColor('#FF3B30')
.fontColor(Color.White).fontSize(16)
.fontWeight(FontWeight.Medium).borderRadius(0)
.onClick(() => { this.deleteItem(item); });
}
@Builder
favoriteButtonBuilder(item: NotificationItem) {
Button('收藏')
.width(80).height('100%')
.backgroundColor('#007AFF')
.fontColor(Color.White).fontSize(16).borderRadius(0)
.onClick(() => { this.favoriteItem(item); });
}
private deleteItem(item: NotificationItem): void {
let index = this.notifications.findIndex(n => n.id === item.id);
if (index !== -1) {
this.notifications.splice(index, 1);
promptAction.showToast({
message: `已删除:「${item.title}」`,
duration: 1500
});
}
}
private favoriteItem(item: NotificationItem): void {
promptAction.showToast({
message: `已收藏:「${item.title}」`,
duration: 1500
});
}
private resetList(): void {
this.notifications = [
new NotificationItem(1, '系统更新提醒', '您的系统已更新至 HarmonyOS NEXT 5.0,点击查看详情。'),
new NotificationItem(2, '新消息通知', '张三 回复了您的评论:"感谢分享!"'),
new NotificationItem(3, '应用下载完成', '《备忘录》应用已下载完成,点击安装。'),
new NotificationItem(4, '安全提醒', '检测到异地登录,建议立即修改密码。'),
new NotificationItem(5, '日历提醒', '您有一个会议将于 15:00 开始,请准时参加。'),
new NotificationItem(6, '订阅更新', '您关注的专栏「鸿蒙开发实战」发布了新文章。'),
];
promptAction.showToast({ message: '列表已重置', duration: 1000 });
}
}
@Component
struct TitleBar {
private title: string = '';
build() {
Row() {
Text(this.title).fontSize(20).fontWeight(FontWeight.Bold).fontColor(Color.White)
}
.width('100%').height(56).backgroundColor('#0A59F7').padding({ left: 20, right: 20 })
}
}
@Component
struct TipBanner {
build() {
Row() {
Text('👉 向右滑动列表项 → 删除 | 👈 向左滑动 → 收藏')
.fontSize(13).fontColor('#666666').textAlign(TextAlign.Center)
}
.width('100%').padding({ top: 12, bottom: 12 }).backgroundColor('#FFEEDD')
}
}
@Component
struct BottomActionBar {
private onReset?: () => void;
build() {
Row() {
Button('🔄 重置列表').width(160).height(40)
.backgroundColor('#0A59F7').fontColor(Color.White).fontSize(15).borderRadius(20)
.onClick(() => { this.onReset?.(); })
}
.width('100%').height(64).justifyContent(FlexAlign.Center)
.backgroundColor(Color.White).shadow({ radius: 4, color: '#20000000' })
}
}
@Component
struct NotificationCard {
private item: NotificationItem = new NotificationItem(0, '', '');
build() {
Row() {
Circle().width(40).height(40).fill('#0A59F7').opacity(0.85)
.margin({ right: 14 })
.overlay(this.iconBuilder(this.item.title.charAt(0)))
Column() {
Text(this.item.title).fontSize(16).fontWeight(FontWeight.Medium)
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis }).width('100%')
Text(this.item.content).fontSize(13).fontColor('#999999')
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis }).width('100%')
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Start).layoutWeight(1)
}
.width('100%').height('100%')
.padding({ left: 16, right: 16 }).backgroundColor(Color.White)
.alignItems(VerticalAlign.Center)
}
@Builder
iconBuilder(char: string) {
Text(char).fontColor(Color.White).fontSize(18).fontWeight(FontWeight.Bold)
}
}
八、常见编译错误与解决方案
在实际开发过程中,ArkTS 编译器会比标准 TypeScript 更加严格。以下是我们踩过的坑和解决方案:
8.1 ERROR: arkts-no-ctor-prop-decls
ERROR: Declaring fields in "constructor" is not supported (arkts-no-ctor-prop-decls)
原因:ArkTS 不支持 TypeScript 中的构造函数参数属性简写(即 constructor(public id: number) 这种写法)。
解决方案:在类体中先声明所有字段并提供默认值,然后在构造函数体中逐个赋值。
// ✅ 正确
class Item {
id: number = 0;
constructor(id: number) {
this.id = id;
}
}
// ❌ 错误
class Item {
constructor(public id: number) {}
}
8.2 ERROR: CustomBuilder 类型不匹配
ERROR: Type 'DeleteButton' is not assignable to type 'CustomBuilder'
原因:.swipeAction() 的 builder 属性要求 CustomBuilder 类型,但直接传入了一个 @Component 结构体的实例。
解决方案:将滑动面板的定义从 @Component 改为 @Builder 函数。
// ✅ 正确
@Builder
deleteButtonBuilder(item: Item) {
Button('删除').onClick(() => { this.deleteItem(item); })
}
// ❌ 错误
.swipeAction({
start: { builder: DeleteButton() }
})
8.3 ERROR: overlay 参数类型不匹配
ERROR: Argument of type 'TextAttribute' is not assignable to parameter of type 'string | CustomBuilder'
原因:Circle().overlay() 方法接受 CustomBuilder 类型,但直接链式调用 .fontColor() 等 Text 属性方法返回的是 TextAttribute,与 CustomBuilder 不兼容。
解决方案:同样使用 @Builder 函数构建 overlay 内容。
// ✅ 正确
Circle()
.overlay(this.iconBuilder(char))
@Builder
iconBuilder(char: string) {
Text(char).fontColor(Color.White).fontSize(18)
}
// ❌ 错误
Circle()
.overlay(Text(char).fontColor(Color.White))
8.4 警告: showToast 已废弃
WARN: 'showToast' has been deprecated.
原因:在 API 24 中,promptAction.showToast() 已被标记为 deprecated,推荐迁移到新的 Toast API。
解决方案:对于 API 24 及以上版本,推荐使用 @ohos.arkui.dialog 模块中的 showToast 方法:
// API 24 推荐方式
import { showToast } from '@ohos.arkui.dialog';
// 使用
showToast({ message: '已删除', duration: 1500 });
不过,promptAction.showToast() 在 API 24 中仍然可以正常工作,只是会有编译警告。如果你暂时不想迁移,可以在 build-profile.json5 的 strictMode 中配置忽略 deprecated 检查,或者简单地继续使用旧 API——不会影响功能。
九、扩展与最佳实践
9.1 多按钮滑动面板
当需要在滑动面板中放置多个按钮时,可以使用 Row 布局:
@Builder
multiActionBuilder(item: NotificationItem) {
Row() {
Button('置顶').width(60).height('100%').backgroundColor('#FF9500')
.onClick(() => { this.pinItem(item); })
Button('标记').width(60).height('100%').backgroundColor('#007AFF')
.onClick(() => { this.markItem(item); })
Button('删除').width(60).height('100%').backgroundColor('#FF3B30')
.onClick(() => { this.deleteItem(item); })
}
}
9.2 确认删除对话框
为了防止误删除,可以在点击删除按钮时弹出确认对话框:
import { AlertDialog } from '@kit.ArkUI';
private confirmDelete(item: NotificationItem): void {
AlertDialog.show({
title: '确认删除',
message: `确定要删除「${item.title}」吗?`,
primaryButton: {
value: '取消',
action: () => {}
},
secondaryButton: {
value: '删除',
fontColor: '#FF3B30',
action: () => { this.deleteItem(item); }
}
});
}
9.3 性能优化:数据量大时的考量
当列表数据超过 100 条时,建议:
- 使用 LazyForEach 替代 ForEach,实现真正的虚拟列表
- 避免复杂的 @Builder 中的嵌套组件,保持滑动面板的轻量化
- 合理设置 ListItem 的高度,尽量固定高度以优化复用效率
// 大数据量时推荐使用 LazyForEach
List() {
LazyForEach(this.dataSource, (item: Item) => {
ListItem() {
ItemView({ item: item })
}
.swipeAction({ /* ... */ })
}, (item: Item) => item.key)
}
9.4 无障碍访问(Accessibility)
为滑动按钮添加无障碍标签,方便视障用户使用:
Button('删除')
.accessibilityText('删除此通知')
.accessibilityDescription('点击后将从此列表中移除该条通知')
十、总结
本文通过一个完整的实战项目,详细讲解了在 HarmonyOS NEXT 中使用 ArkTS 实现 List 滑动删除(SwipeToDelete) 的全部技术细节。
核心要点回顾
| 知识点 | 核心内容 |
|---|---|
| List 组件 | 高性能列表容器,支持懒加载和复用 |
| .swipeAction() | ListItem 的滑动操作 API,支持 start/end 双方向 |
| @Builder 与 @Component | 滑动面板必须使用 @Builder(CustomBuilder),不能用 @Component |
| @State 响应式数据 | 修改 @State 数组自动触发 UI 刷新 |
| ForEach key 生成器 | 为每个列表项提供唯一 key,优化 Diff 效率 |
| ArkTS 语法约束 | 构造函数不能参数声明字段;overlay 需要 @Builder |
适用场景
- 邮件列表中的滑动标记已读/删除
- 聊天列表的滑动删除/置顶
- 待办事项应用的滑动完成/删除
- 文件管理器的滑动更多操作
- 任何需要快捷操作的列表界面
项目源码
本项目的完整代码位于 entry/src/main/ets/pages/SwipeToDeleteDemo.ets,已通过 API 24 编译验证。你可以直接将其导入到 DevEco Studio 中运行,体验滑动删除的流畅交互。
附录:参考资源
本文由 AtomCode (deepseek-v4-flash) 基于实际项目编译验证生成。博客文件路径:Blog_SwipeToDelete_HarmonyOS_NEXT.md
更多推荐



所有评论(0)