iOS触摸与手势开发实战
在iOS开发中,处理触摸和手势是构建交互性应用的重要部分。本文将详细介绍如何处理触摸事件及实现常见手势识别,同时会通过两个具体应用示例进行说明。
触摸事件基础
在处理触摸事件时,并非所有触摸对象都与当前视图或视图控制器相关。例如,表格视图单元格可能不关心其他行或导航栏上的触摸。可以通过以下代码获取特定视图内的触摸集合:
let myTouches = event.touchesForView(self.view)
每个
UITouch
对象代表一根手指,可通过它获取手指在屏幕上的位置,还能将该位置转换为视图的本地坐标系:
let point = touch.locationInView(self.view) // point是CGPoint类型
以下是几个重要的触摸相关方法:
1.
touchesMoved(_, withEvent:)
:当用户手指在屏幕上移动时会多次调用该方法,每次调用都会得到一组新的触摸对象和事件。除了能获取手指当前位置,还能获取上次调用
touchesMoved(_, withEvent:)
或
touchesBegan(_, withEvent:)
时手指的位置。
2.
touchesEnded(_, withEvent:)
:当用户手指离开屏幕时调用,表明一次手势操作结束。
3.
touchesCancelled(_, withEvent:)
:当用户在进行手势操作时被中断(如来电)会调用该方法。调用此方法后,当前手势不会再调用
touchesEnded(_, withEvent:)
。
TouchExplorer应用实践
为了更好地理解上述四个触摸相关方法的调用时机,我们来构建一个
TouchExplorer
应用。
1.
创建项目
:在Xcode中使用单视图应用模板创建新项目,产品名称为
TouchExplorer
,设备选择
Universal
。
2.
添加标签
:该应用需要三个标签,分别用于显示最后调用的方法、当前点击次数和触摸次数。在
ViewController.swift
中添加以下代码:
class ViewController: UIViewController {
@IBOutlet var messageLabel:UILabel!
@IBOutlet var tapsLabel:UILabel!
@IBOutlet var touchesLabel:UILabel!
}
-
编辑GUI
:选择
Main.storyboard编辑界面,拖放一个标签到视图左上角,按住Option键再拖出两个标签,使其上下排列。 -
设置约束
:在文档大纲中,从第一个标签按住
Control键拖动到主视图,按住Shift键选择“Top Space to Top Layout Guide”和“Leading Space to Container Margin”,对其他两个标签执行相同操作。 -
连接标签
:从视图控制器图标按住
Control键拖动到三个标签,分别连接到对应的出口。 -
清除标签文本
:双击每个标签并按
Delete键清除文本。 - 启用交互 :点击视图背景或文档大纲中的视图图标,打开属性检查器,确保“User Interaction Enabled”和“Multiple Touch”都被勾选。
-
修改代码
:在
ViewController.swift中添加以下代码:
class ViewController: UIViewController {
@IBOutlet var messageLabel:UILabel!
@IBOutlet var tapsLabel:UILabel!
@IBOutlet var touchesLabel:UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// 加载视图后进行额外设置,通常从nib加载
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// 释放可重新创建的资源
}
func updateLabelsFromTouches(touches:NSSet!) {
let touch = touches.anyObject() as UITouch
let numTaps = touch.tapCount
let tapsMessage = "\(numTaps) taps detected"
tapsLabel.text = tapsMessage
let numTouches = touches.count
let touchMsg = "\(numTouches) touches detected"
touchesLabel.text = touchMsg
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
messageLabel.text = "Touches Began"
updateLabelsFromTouches(event.allTouches())
}
override func touchesCancelled(touches: NSSet, withEvent event: UIEvent) {
messageLabel.text = "Touches Cancelled"
updateLabelsFromTouches(event.allTouches())
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
messageLabel.text = "Touches Ended"
updateLabelsFromTouches(event.allTouches())
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
messageLabel.text = "Drag Detected"
updateLabelsFromTouches(event.allTouches())
}
}
在这个控制器类中,实现了四个触摸相关方法,每个方法都会设置
messageLabel
以显示调用时机,并调用
updateLabelsFromTouches()
更新其他两个标签。
9.
编译运行
:编译并运行应用。在模拟器中,可多次点击屏幕增加点击次数,点击并按住鼠标拖动模拟触摸和拖动操作。还可以通过按住
Option
键模拟双指捏合,按住
Option
和
Shift
键模拟双指滑动。
Swipes应用实践
接下来构建一个
Swipes
应用,用于检测水平和垂直滑动手势。
1.
创建项目
:在Xcode中使用单视图应用模板创建新项目,设备选择
Universal
,项目名称为
Swipes
。
2.
添加代码
:在
ViewController.swift
中添加以下代码:
class ViewController: UIViewController {
@IBOutlet var label:UILabel!
private var gestureStartPoint:CGPoint!
}
-
编辑界面
:选择
Main.storyboard,确保视图的“User Interaction Enabled”和“Multiple Touch”都被勾选。从库中拖动一个标签到视图上部,设置文本居中,调整其他文本属性。在文档大纲中,从标签按住Control键拖动到视图,按住Shift键选择“Top Space to Top Layout Guide”和“Center Horizontally in Container”。从视图控制器图标按住Control键拖动到标签,连接到label出口,双击标签删除文本。 -
进一步添加代码
:在
ViewController.swift中继续添加以下代码:
class ViewController: UIViewController {
@IBOutlet var label:UILabel!
private var gestureStartPoint:CGPoint!
private let minimumGestureLength = Float(25.0)
private let maximumVariance = Float(5)
override func viewDidLoad() {
super.viewDidLoad()
// 加载视图后进行额外设置,通常从nib加载
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// 释放可重新创建的资源
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject() as UITouch
gestureStartPoint = touch.locationInView(self.view)
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject() as UITouch
let currentPosition = touch.locationInView(self.view)
let deltaX = fabsf(Float(gestureStartPoint.x - currentPosition.x))
let deltaY = fabsf(Float(gestureStartPoint.y - currentPosition.y))
if deltaX >= minimumGestureLength && deltaY <= maximumVariance {
label.text = "Horizontal swipe detected"
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
{ self.label.text = "" })
} else if deltaY >= minimumGestureLength && deltaX <= maximumVariance {
label.text = "Vertical swipe detected"
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
{ self.label.text = "" })
}
}
}
在
touchesBegan(_, withEvent:)
方法中,获取触摸点并存储。在
touchesMoved(_, withEvent:)
方法中,计算手指水平和垂直移动的距离,判断是否构成滑动手势。如果构成,则设置标签文本并在2秒后清除。
5.
编译运行
:编译并运行应用,在模拟器中进行滑动操作测试。
自动手势识别
iOS提供了
UIGestureRecognizer
类,可简化手势识别的实现。以下是修改
Swipes
应用使用手势识别器的步骤:
1.
删除原有方法
:在
ViewController.swift
中删除
touchesBegan(_, withEvent:)
和
touchesMoved(_, withEvent:)
方法。
2.
添加新方法
:添加以下方法:
func reportHorizontalSwipe(recognizer:UIGestureRecognizer) {
label.text = "Horizontal swipe detected"
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
{ self.label.text = "" })
}
func reportVerticalSwipe(recognizer:UIGestureRecognizer) {
label.text = "Vertical swipe detected"
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
{ self.label.text = "" })
}
- 修改viewDidLoad方法 :
override func viewDidLoad() {
super.viewDidLoad()
// 加载视图后进行额外设置,通常从nib加载
let vertical = UISwipeGestureRecognizer(target: self, action: "reportVerticalSwipe:")
vertical.direction = .Up | .Down
view.addGestureRecognizer(vertical)
let horizontal = UISwipeGestureRecognizer(target: self, action: "reportHorizontalSwipe:")
horizontal.direction = .Left | .Right
view.addGestureRecognizer(horizontal)
}
这里创建了两个手势识别器,分别用于检测垂直和水平滑动。当识别到相应手势时,调用对应的方法设置标签文本。
4.
清理代码
:可以删除
gestureStartPoint
属性声明和两个常量值。
5.
编译运行
:编译并运行应用,测试新的手势识别器。
实现多手指滑动
之前的
Swipes
应用只处理单手指滑动,若要处理多手指滑动,可通过配置
UISwipeGestureRecognizer
来实现。
1.
修改viewDidLoad方法
:
override func viewDidLoad() {
super.viewDidLoad()
// 加载视图后进行额外设置,通常从nib加载
for var touchCount = 1; touchCount <= 5; touchCount++ {
let vertical = UISwipeGestureRecognizer(target: self, action: "reportVerticalSwipe:")
vertical.direction = .Up | .Down
vertical.numberOfTouchesRequired = touchCount
view.addGestureRecognizer(vertical)
let horizontal = UISwipeGestureRecognizer(target: self, action: "reportHorizontalSwipe:")
horizontal.direction = .Left | .Right
horizontal.numberOfTouchesRequired = touchCount
view.addGestureRecognizer(horizontal)
}
}
通过循环创建多个手势识别器,每个识别器可识别不同数量的手指滑动。
2.
添加描述方法
:在
ViewController
类底部添加以下方法:
func descriptionForTouchCount(touchCount:Int) -> String {
switch touchCount {
case 1:
return "Single"
case 2:
return "Double"
case 3:
return "Triple"
case 4:
return "Quadruple"
case 5:
return "Quintuple"
default:
return ""
}
}
- 修改报告方法 :修改两个滑动报告方法:
func reportHorizontalSwipe(recognizer:UIGestureRecognizer) {
label.text = "Horizontal swipe detected"
let count = descriptionForTouchCount(recognizer.numberOfTouches())
label.text = "\(count) Horizontal swipe detected"
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
{ self.label.text = "" })
}
这样,不同数量手指的滑动会有相应的描述显示在标签上。
通过以上步骤,我们详细介绍了iOS中触摸事件的处理和手势识别的实现,从基础的触摸方法到使用手势识别器,再到多手指滑动的处理,希望能帮助你更好地开发具有交互性的iOS应用。
以下是一个简单的流程图,展示了
Swipes
应用使用手势识别器的流程:
graph TD;
A[启动应用] --> B[创建手势识别器];
B --> C[添加到视图];
C --> D[等待手势];
D --> E{识别到手势?};
E -- 是 --> F[调用相应方法];
F --> G[设置标签文本];
G --> H[2秒后清除文本];
E -- 否 --> D;
同时,为了更清晰地对比手动处理滑动和使用手势识别器的代码差异,以下是一个简单的表格:
| 方法 | 手动处理滑动 | 使用手势识别器 |
| ---- | ---- | ---- |
| 代码复杂度 | 较高,需要手动计算手指移动距离和判断 | 较低,只需创建识别器并配置 |
| 可读性 | 相对较低,涉及较多数学计算 | 较高,代码逻辑清晰 |
| 扩展性 | 较难实现复杂手势和多手指滑动 | 容易配置不同数量手指的滑动和复杂手势 |
iOS触摸与手势开发实战
多手指滑动配置详解
在实现多手指滑动时,我们通过循环创建了多个
UISwipeGestureRecognizer
实例。下面详细解释每个步骤的作用和好处。
首先是修改
viewDidLoad
方法的循环部分:
override func viewDidLoad() {
super.viewDidLoad()
// 加载视图后进行额外设置,通常从nib加载
for var touchCount = 1; touchCount <= 5; touchCount++ {
let vertical = UISwipeGestureRecognizer(target: self, action: "reportVerticalSwipe:")
vertical.direction = .Up | .Down
vertical.numberOfTouchesRequired = touchCount
view.addGestureRecognizer(vertical)
let horizontal = UISwipeGestureRecognizer(target: self, action: "reportHorizontalSwipe:")
horizontal.direction = .Left | .Right
horizontal.numberOfTouchesRequired = touchCount
view.addGestureRecognizer(horizontal)
}
}
- 循环目的 :通过循环从1到5,为每个触摸数量(即手指数量)创建垂直和水平的滑动手势识别器。这样可以让应用识别从单指到五指的滑动操作。
-
手势识别器配置
:
-
target: self:指定手势识别器触发时调用方法的对象为当前视图控制器。 -
action: "reportVerticalSwipe:"或"reportHorizontalSwipe:":指定手势识别成功时调用的方法。 -
direction:设置手势的方向,.Up | .Down表示垂直方向,.Left | .Right表示水平方向。 -
numberOfTouchesRequired = touchCount:指定该手势识别器需要的触摸数量,也就是手指数量。
-
接着是添加的描述方法:
func descriptionForTouchCount(touchCount:Int) -> String {
switch touchCount {
case 1:
return "Single"
case 2:
return "Double"
case 3:
return "Triple"
case 4:
return "Quadruple"
case 5:
return "Quintuple"
default:
return ""
}
}
这个方法通过
switch
语句根据触摸数量返回对应的描述字符串,方便在报告滑动时显示更详细的信息。
最后修改的报告方法:
func reportHorizontalSwipe(recognizer:UIGestureRecognizer) {
label.text = "Horizontal swipe detected"
let count = descriptionForTouchCount(recognizer.numberOfTouches())
label.text = "\(count) Horizontal swipe detected"
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
{ self.label.text = "" })
}
在这个方法中,先设置初始的滑动检测信息,然后通过
descriptionForTouchCount
方法获取触摸数量的描述,并更新标签文本。最后使用
dispatch_after
在2秒后清除标签文本,以便用户可以进行多次滑动操作。
手势识别器的优势总结
使用
UISwipeGestureRecognizer
等手势识别器具有以下明显优势:
1.
代码简洁
:相比手动处理触摸事件来检测滑动,使用手势识别器的代码量大大减少,逻辑更加清晰。例如,手动处理滑动需要在
touchesBegan
和
touchesMoved
方法中进行复杂的计算和判断,而使用手势识别器只需要创建和配置识别器即可。
2.
易于扩展
:可以轻松配置不同数量的手指滑动和复杂手势。如上述的多手指滑动实现,通过简单的循环和配置就能实现从单指到五指的滑动识别。
3.
可读性高
:代码逻辑更符合人类思维,易于理解和维护。开发者不需要关注底层的触摸事件处理细节,只需要关注手势识别成功后的操作。
自定义手势识别器的展望
虽然iOS提供了丰富的内置手势识别器,但在某些场景下,可能需要自定义手势识别器来满足特定的需求。例如,应用需要识别一些独特的手势组合,如特定形状的滑动轨迹。
自定义手势识别器的基本步骤如下:
1.
继承
UIGestureRecognizer
类
:创建一个新的类,继承自
UIGestureRecognizer
。
2.
重写方法
:重写
touchesBegan
、
touchesMoved
、
touchesEnded
和
touchesCancelled
等方法,在这些方法中实现自定义的手势识别逻辑。
3.
状态管理
:根据手势的识别情况,设置手势识别器的状态,如
.began
、
.changed
、
.ended
等。
以下是一个简单的自定义手势识别器流程图:
graph TD;
A[启动应用] --> B[创建自定义手势识别器];
B --> C[等待触摸事件];
C --> D{触摸开始?};
D -- 是 --> E[调用touchesBegan];
E --> F{手势识别中?};
F -- 是 --> G[调用touchesMoved];
G --> F;
F -- 否 --> H{触摸结束?};
H -- 是 --> I[调用touchesEnded];
I --> J{手势识别成功?};
J -- 是 --> K[设置状态为.ended并触发操作];
J -- 否 --> L[设置状态为.failed];
H -- 否 --> M{触摸取消?};
M -- 是 --> N[调用touchesCancelled并设置状态为.cancelled];
D -- 否 --> C;
总结
通过本文的介绍,我们深入了解了iOS中触摸事件的处理和手势识别的实现。从基础的触摸事件获取和处理,到使用内置的手势识别器简化开发,再到实现多手指滑动和展望自定义手势识别器,我们逐步掌握了构建交互性iOS应用的关键技术。
在实际开发中,建议优先使用内置的手势识别器,因为它们具有代码简洁、易于扩展和可读性高的优点。当内置识别器无法满足需求时,再考虑自定义手势识别器。希望这些知识能帮助你开发出更加丰富和交互性强的iOS应用。
以下是一个总结性的列表,回顾本文的主要内容:
1. 触摸事件基础:了解如何获取特定视图内的触摸集合和手指位置,以及重要的触摸相关方法。
2.
TouchExplorer
应用:通过该应用实践,掌握触摸事件处理方法的调用时机和标签更新操作。
3.
Swipes
应用:实现水平和垂直滑动手势的检测,包括手动处理和使用手势识别器两种方式。
4. 多手指滑动:通过配置
UISwipeGestureRecognizer
实现不同数量手指的滑动识别。
5. 手势识别器优势:代码简洁、易于扩展和可读性高。
6. 自定义手势识别器:展望自定义手势识别器的实现步骤和应用场景。
超级会员免费看
139

被折叠的 条评论
为什么被折叠?



