【HarmonyOS开发小实践】ArkUI 交互事件与手势:从触摸到组合手势
ArkUI 交互事件与手势:从触摸到组合手势
交互是界面和用户的对话
组件画好了、动画做好了,最终要响应"用户怎么操作"。ArkUI 的交互分两层:通用事件(触摸、点击、键盘、焦点)和手势事件(长按、拖动、捏合、旋转、滑动)。手势事件是基于通用事件进一步识别的结果。
用户操作
↓
通用事件:触摸、鼠标、键盘、焦点(底层原始事件)
↓ 框架识别
手势事件:单击、长按、拖动、捏合、旋转、滑动(识别后的语义)
↓ 组合
组合手势:多个手势组合(如双指缩放 + 拖动)
通用事件:Click 和 Touch
最基础的是 onClick,几乎每个组件都支持:
Button('点击我')
.onClick(() => {
console.info('按钮被点击');
})
触摸事件 onTouch 提供更底层的触摸信息:
Text('触摸区域')
.onTouch((event: TouchEvent) => {
switch (event.type) {
case TouchType.Down:
console.info('手指按下');
break;
case TouchType.Move:
console.info('手指移动');
break;
case TouchType.Up:
console.info('手指抬起');
break;
}
})
onTouch 能拿到触摸的坐标、类型(Down/Move/Up),适合做跟手操作。普通点击用 onClick 就够,需要精细控制才用 onTouch。
单击手势 TapGesture
onClick 是简化的点击,TapGesture 是完整的手势点击,能设置点击次数:
Text('双击我')
.gesture(
TapGesture({ count: 2 }) // 双击
.onAction((event: GestureEvent) => {
console.info('双击触发');
})
)
count: 2 表示双击,count: 1 是单击。需要区分单击双击时用 TapGesture。
长按手势 LongPressGesture
Text('长按我')
.gesture(
LongPressGesture({ repeat: false })
.onAction((event: GestureEvent) => {
console.info('长按触发');
})
)
长按常用于:弹出上下文菜单、删除确认、拖拽触发。repeat 控制是否重复触发(长按不动时是否连续回调)。
拖动手势 PanGesture
@Entry
@Component
struct PanDemo {
@State offsetX: number = 0;
@State offsetY: number = 0;
build() {
Text('拖动我')
.width(80)
.height(80)
.backgroundColor('#FF6B35')
.offset({ x: this.offsetX, y: this.offsetY })
.gesture(
PanGesture()
.onActionUpdate((event: GestureEvent) => {
// 拖动过程中持续回调,更新位置实现跟手
this.offsetX += event.offsetX;
this.offsetY += event.offsetY;
})
)
}
}
onActionUpdate 在拖动过程中持续触发,event.offsetX/Y 是单次位移量,累加实现跟手效果。拖动是移动元素的基础手势。
捏合与旋转:双指手势
捏合(缩放)和旋转需要双指:
@Entry
@Component
struct PinchRotateDemo {
@State scale: number = 1.0;
@State angle: number = 0;
build() {
Text('双指缩放旋转')
.scale({ x: this.scale, y: this.scale })
.rotate({ angle: this.angle })
.gesture(
GestureGroup(GestureMode.Parallel,
// 双指捏合缩放
PinchGesture()
.onActionUpdate((event: GestureEvent) => {
this.scale *= event.scale; // event.scale 是缩放比例
}),
// 双指旋转
RotationGesture()
.onActionUpdate((event: GestureEvent) => {
this.angle += event.angle; // event.angle 是旋转角度
})
)
)
}
}
GestureGroup 组合多个手势,GestureMode.Parallel 表示同时识别(缩放和旋转可同时进行)。
滑动手势 SwipeGesture
Text('滑动区域')
.gesture(
SwipeGesture()
.onAction((event: GestureEvent) => {
// 根据滑动方向处理
if (event.angle >= 45 && event.angle < 135) {
console.info('向上滑动');
} else {
console.info('其他方向滑动');
}
})
)
滑动常用于:翻页、切换 tab、侧滑返回。event.angle 是滑动角度,用来判断方向。
手势组合:GestureGroup
多个手势组合是手势能力的核心。GestureGroup 有三种模式:
| 模式 | 含义 | 示例 |
|---|---|---|
GestureMode.Parallel | 并行识别,多个手势同时响应 | 缩放 + 旋转同时进行 |
GestureMode.Sequence | 顺序识别,一个手势完成后另一个才开始 | 长按后拖动(先长按再拖) |
GestureMode.Exclusive | 互斥,只识别其中一个 | 单击和双击二选一 |
顺序识别的典型场景——长按后拖动:
Text('长按后拖动')
.gesture(
GestureGroup(GestureMode.Sequence,
LongPressGesture() // 先长按
.onAction(() => {
console.info('长按激活');
}),
PanGesture() // 再拖动
.onActionUpdate((event: GestureEvent) => {
console.info('拖动中');
})
)
)
互斥识别——区分单击和双击:
Text('单击或双击')
.gesture(
GestureGroup(GestureMode.Exclusive,
TapGesture({ count: 1 })
.onAction(() => console.info('单击')),
TapGesture({ count: 2 })
.onAction(() => console.info('双击'))
)
)
焦点事件
焦点事件主要用于键盘/遥控器导航场景:
Text('可聚焦组件')
.focusable(true) // 允许获取焦点
.onFocus(() => {
console.info('获得焦点');
})
.onBlur(() => {
console.info('失去焦点');
})
手机 app 的触屏场景焦点事件用得少,但做 TV 应用、无障碍导航时是基础。
小总结
-
手势会拦截组件默认行为。给组件加了
gesture可能影响其默认手势(如列表的滚动)。需要时用priorityGesture让手势优先,或用parallelGesture并行。 -
拖动注意坐标累积。
PanGesture的event.offsetX/Y是单次增量,要累加到@State上。直接赋值会跳动不跟手。 -
组合手势用对模式。并行、顺序、互斥三种模式语义完全不同,用错模式手势会互相冲突,出现"怎么都不触发"或"同时触发"的奇怪现象。
-
触摸和手势别叠加混用。同一组件既用
onTouch又用gesture容易冲突。底层细节用onTouch,语义操作用手势,二选一。 -
长按手势的
repeat默认 false。如果希望长按不放持续触发(如音量连调),需要显式设置repeat: true。
更多推荐
所有评论(0)