现在已有内置组件「多点触控」:双击、长按、滑动、双指缩放和旋转、多点追踪都不用再导入拓展,推荐直接使用。
概述
App Inventor 2的Canvas和Screen只有基本的Touch/Dragged/Fling事件。手势识别扩展(GestureDetector)可以识别更丰富的手势:
| 手势 | 内置支持 | 扩展支持 |
|---|---|---|
| 单击 | ✅ Touched | ✅ |
| 双击 | ❌ | ✅ onDoubleTap |
| 长按 | ❌ | ✅ onLongPress |
| 滑动 | ✅ Flung | ✅ onFling(更精确) |
| 缩放(捏合) | ❌ | ✅ onScale |
| 滚动 | 部分(Dragged) | ✅ onScroll |
| 多点触控 | ❌ | ✅ Multitouch扩展 |
已有文档参考
other/extensionsGestures.md— 手势扩展基础文档other/extensionsMultitouch.md— 多点触控扩展other/extensionsRotation.md— 旋转手势扩展
本文在已有文档基础上,补充具体的使用场景和集成方案。
GestureDetector扩展
导入扩展
- 下载 GestureDetector扩展(.aix文件)
- Designer → Extension → Import Extension → 选择.aix
核心事件
when GestureDetector1.DoubleTapAtPoint(X, Y) {
// 双击触发
标签_状态.Text = join("双击 @ ", X, ",", Y)
}
when GestureDetector1.LongClick(X, Y) {
// 长按触发
标签_状态.Text = join("长按 @ ", X, ",", Y)
}
when GestureDetector1.ThumbEnabled(起点X, 起点Y, 终点X, 终点Y, 速度X, 速度Y) {
// 滑动方向判断
var dX = 终点X - 起点X
var dY = 终点Y - 起点Y
if abs(dX) > abs(dY) {
if dX > 0 {
标签_状态.Text = "👉 右滑"
} else {
标签_状态.Text = "👈 左滑"
}
} else {
if dY > 0 {
标签_状态.Text = "👇 下滑"
} else {
标签_状态.Text = "👆 上滑"
}
}
}
关联组件
GestureDetector需要关联到一个可视组件(如Canvas或Image):
when Screen1.Initialize() {
GestureDetector1.设置目标组件(画布1)
}
实战案例:图片浏览器手势
功能
- 左右滑动切换图片
- 双击放大/缩小
- 长按保存图片
- 上下滑动显示/隐藏工具栏
global 图片列表 = ["pic1.png", "pic2.png", "pic3.png", "pic4.png"]
global 当前索引 = 1
global 是否放大 = false
when Screen1.Initialize() {
GestureDetector1.SetTarget(图像1)
图像1.Picture = selectListItem(图片列表, 1)
}
when GestureDetector1.OnSwipe(startX, startY, endX, endY, speedX, speedY) {
global dX = endX - startX
if (math.abs(dX) > 50) { // 滑动距离阈值
if ((dX > 0) and (当前索引 > 1)) {
global 当前索引 = 当前索引 - 1
图像1.Picture = selectListItem(图片列表, 当前索引)
} else if ((dX < 0) and (当前索引 < lengthOfList(图片列表))) {
global 当前索引 = 当前索引 + 1
图像1.Picture = selectListItem(图片列表, 当前索引)
}
标签_页码.Text = join(当前索引, "/", lengthOfList(图片列表))
}
}
when GestureDetector1.OnDoubleTap(X, Y) {
if (是否放大) {
图像1.WidthPercent = 90
图像1.Height = -1 // Auto
global 是否放大 = false
} else {
图像1.WidthPercent = 200
图像1.HeightPercent = 200
global 是否放大 = true
}
}
when GestureDetector1.OnLongPress(X, Y) {
文件增强1.CopyFile(图像1.Picture, join("/sdcard/DCIM/收藏图片_", 当前索引, ".png"))
Notifier1.ShowMessageDialog("图片已保存到相册", "已保存", "确定")
}
实战案例:手势密码锁
功能
- 在Canvas上画手势路径
- 记录触摸经过的格子
- 验证手势密码
global 网格大小 = 3 // 3x3网格
global 格子坐标 = []
global 手势路径 = []
global 正在画 = false
global 正确密码 = "1-2-3-6-9" // 示例密码路径
when Screen1.Initialize() {
// 计算格子中心坐标
global 格子宽 = 画布1.Width / 网格大小
global 格子高 = 画布1.Height / 网格大小
global i = 0
while (i < 9) {
global 行 = math.floor(i / 网格大小)
global 列 = modulo(i, 网格大小)
global 中心X = 列 * 格子宽 + 格子宽 / 2
global 中心Y = 行 * 格子高 + 格子高 / 2
addItemsTo(格子坐标, create_dictionary("id", (i + 1), "x", 中心X, "y", 中心Y))
global i = i + 1
}
绘制网格()
}
when 画布1.TouchDown(x, y) {
global 正在画 = true
global 手势路径 = []
检查格子(x, y)
}
when 画布1.Dragged(startX, startY, prevX, prevY, currentX, currentY, draggedAnySprite) {
if (draggedAnySprite) {
检查格子(currentX, currentY)
// 画线连接
画布1.DrawLine(prevX, prevY, currentX, currentY)
}
}
procedure 检查格子(X, Y) {
global i = 1
while (i <= lengthOfList(格子坐标)) {
global 格子 = selectListItem(格子坐标, i)
global 格X = Dictionary.Get(格子, "x")
global 格Y = Dictionary.Get(格子, "y")
global 格ID = Dictionary.Get(格子, "id")
global 距离 = math.sqrt((X - 格X) * (X - 格X) + (Y - 格Y) * (Y - 格Y))
if ((距离 < 40) and (not(is_in_list(格ID, 手势路径)))) {
addItemsTo(手势路径, 格ID)
// 高亮选中的格子
画布1.DrawCircle(格X, 格Y, 30, true)
}
global i = i + 1
}
}
when 按钮_验证.Click() {
global 路径文本 = join(手势路径)
if (路径文本 == 正确密码) {
标签_结果.Text = "✅ 密码正确"
openAnotherScreen("Screen_Main")
} else {
标签_结果.Text = "❌ 密码错误"
}
}
Multitouch多点触控
参考已有文档 other/extensionsMultitouch.md,此处补充关键用法:
global 手指计数 = 0
when Multitouch1.TouchDown(指针ID, X, Y) {
global 手指计数 = 手指计数 + 1
标签_手指.Text = join("触摸点:", 手指计数)
}
when Multitouch1.TouchMove(指针ID, X, Y) {
// 多指拖拽处理
if (手指计数 == 2) {
// 双指缩放
global 距离 = 计算两点距离(手指1X, 手指1Y, 手指2X, 手指2Y)
global 缩放比 = 距离 / 初始距离
图像1.Width = 初始宽度 * 缩放比
}
}
when Multitouch1.TouchUp(指针ID, X, Y) {
global 手指计数 = 手指计数 - 1
}
常见问题
Q1: 手势扩展和Canvas事件冲突?
设置优先级:手势扩展和Canvas事件可能同时触发。解决:
- 用手势扩展处理复杂手势(双击、长按)
- 用Canvas事件处理绘制相关
- 设置标志变量控制
Q2: 手势识别灵敏度如何调整?
大多数手势扩展有阈值参数:
CONFIRM_THRESHOLD— 确认阈值VELOCITY_THRESHOLD— 速度阈值- 根据实际体验微调
Q3: 如何实现下拉刷新?
when GestureDetector1.OnSwipe(startX, startY, endX, endY, speedX, speedY) {
global dY = endY - startY
if ((dY > 100) and (speedY > 500)) { // 下拉距离够且速度够
// 触发刷新
刷新数据()
}
}
总结
| 手势 | 方案 | 推荐扩展 |
|---|---|---|
| 单击 | 内置Touched | 不需要 |
| 双击 | GestureDetector | GestureDetector |
| 长按 | GestureDetector | GestureDetector |
| 滑动方向 | 内置Flung或扩展 | GestureDetector |
| 缩放 | Multitouch | Multitouch |
| 旋转 | Rotation扩展 | Rotation |
| 多指 | Multitouch | Multitouch |
扫码添加客服咨询