iOS开发:绘图与手势处理
一、Quartz和OpenGL绘图更新
在iOS开发中,如果要从Quartz绘图切换到OpenGL ES绘图,需要进行一系列的更新操作。
1. 更新BIDViewController
在 BIDViewController.m 文件中,需要做一些小的更改:
- 替换头文件引用 :将 #import "BIDQuartzFunView.h" 替换为 #import "BIDGLFunView.h" 。
- 修改 changeColor: 方法 :将原来的 changeColor: 方法替换为以下版本:
- (IBAction)changeColor:(id)sender {
UISegmentedControl *control = sender;
NSInteger index = [control selectedSegmentIndex];
BIDGLFunView *glView = (BIDGLFunView *)self.view;
switch (index) {
case kRedColorTab:
glView.currentColor = [UIColor redColor];
glView.useRandomColor = NO;
break;
case kBlueColorTab:
glView.currentColor = [UIColor blueColor];
glView.useRandomColor = NO;
break;
case kYellowColorTab:
glView.currentColor = [UIColor yellowColor];
glView.useRandomColor = NO;
break;
case kGreenColorTab:
glView.currentColor = [UIColor greenColor];
glView.useRandomColor = NO;
break;
case kRandomColorTab:
glView.useRandomColor = YES;
break;
default:
break;
}
}
- 修改
changeShape:方法 :将[(BIDQuartzFunView *)self.view setShapeType:[control selectedSegmentIndex]];修改为[(BIDGLFunView *)self.view setShapeType:[control selectedSegmentIndex]];。
2. 更新Nib文件
由于是从QuartzFun项目复制而来,视图仍然配置为使用 BIDQuartzFunView 作为其底层类,需要将其更改为 BIDGLFunView 。具体操作步骤如下:
1. 双击 BIDViewController.xib 打开Interface Builder。
2. 单击Dock中的Quartz Fun View。
3. 按下相应快捷键(文档中为 3 ,可能是特定软件环境下的快捷键)调出身份检查器。
4. 将类从 BIDQuartzFunView 更改为 BIDGLFunView 。
3. 完成GLFun项目
在编译和运行此程序之前,需要将两个框架链接到项目中:
1. 按照添加音频工具箱框架的类似步骤(在“链接音频工具箱框架”部分)进行操作。
2. 选择 OpenGLES.framework 和 QuartzCore.framework ,而不是 AudioToolbox.framework 。
添加框架后,运行项目,它应该看起来与Quartz版本相同。
二、iOS设备的手势处理
iOS设备的多点触控屏幕是其强大可用性的关键因素之一,它能够检测多种手势,为用户提供超越界面的操作能力。
1. 多点触控术语
在深入了解手势处理架构之前,先了解一些基本词汇:
- 手势(Gesture) :从一个或多个手指触摸屏幕到手指离开屏幕的一系列事件序列。Cocoa Touch没有公开表示手势的类或结构,运行的应用程序可以监视用户输入流来判断是否有手势发生。
- 事件(Event) :与设备的多点触控屏幕交互时生成的,包含触摸信息。
- 触摸(Touch) :手指放在屏幕上、在屏幕上拖动或从屏幕上抬起的动作。一个手势中涉及的触摸次数等于同一时间屏幕上的手指数量。
- 点击(Tap) :手指触摸屏幕后立即抬起,不移动。iOS设备可以跟踪点击次数,区分单点击、双击、三击等。
- 手势识别器(Gesture Recognizer) :能够监视用户生成的事件流,并识别用户触摸和拖动方式是否符合预定义手势的对象。 UIGestureRecognizer 类及其各种子类可以帮助简化常见手势的监测工作。
2. 响应链
手势通过事件在系统中传递,而事件通过响应链传递,因此了解响应链的工作原理对于正确处理手势至关重要。
响应链的工作流程如下:
graph LR
A[第一响应者] -->|不处理事件| B[视图控制器]
B -->|不处理事件| C[父视图]
C -->|有控制器| D[父视图控制器]
D -->|不处理事件| E[应用程序窗口]
E -->|不处理事件| F[UIApplication对象]
F -->|不处理事件| G[应用程序委托]
G -->|不处理事件| H[事件丢弃]
常见的响应者包括视图、控件、视图控制器等,它们都继承自 UIResponder 类。如果第一响应者不处理某个事件,它会将事件传递给响应链中的下一个对象。如果某个对象响应了事件,通常会消耗该事件,阻止其继续在响应链中传递。
例如,当用户在表格的某一行上滑动手指时,手势的处理过程如下:
1. 如果滑动发生在表格视图单元格的子视图或控件内,该视图或控件有机会响应。
2. 如果它不响应,表格视图单元格有机会响应。
3. 如果表格视图单元格不响应,事件将继续向上传递,直到有对象响应或到达响应链的末尾。
在某些情况下,如果响应者只部分处理事件,它会采取行动并将事件转发给响应链中的下一个响应者。例如,假设邮件应用中的表格视图单元格只处理删除滑动手势,对于其他手势,它需要手动将事件转发给下一个对象,以确保其他视图有机会响应。示例代码如下:
-(void)respondToFictionalEvent:(UIEvent *)event {
if (someCondition)
[self handleEvent:event];
else
[self.nextResponder respondToFictionalEvent:event];
}
三、手势处理代码的位置
手势处理代码通常可以嵌入 UIView 的子类或 UIViewController 中。
- 视图类 :如果视图需要根据用户的触摸对自身进行操作,代码可能属于定义该视图的类。例如, UISwitch 和 UISlider 等控件类会响应与触摸相关的事件。
- 视图控制器类 :当处理的手势影响的不仅仅是被触摸的对象时,手势代码通常属于视图的控制器类。例如,用户通过触摸一行来指示删除所有行的手势,应该由视图控制器中的代码处理。
四、四个触摸通知方法
有四个方法用于通知响应者关于触摸的信息:
| 方法名称 | 说明 |
| ---- | ---- |
| touchesBegan:withEvent: | 用户首次触摸屏幕时调用,可用于检测手势开始或点击屏幕。 |
| touchesMoved:withEvent: | 用户手指在屏幕上移动时多次调用,可获取手指当前和上一次的位置。 |
| touchesEnded:withEvent: | 用户手指从屏幕上移除时调用,表示手势结束。 |
| touchesCancelled:withEvent: | 用户在手势进行中被中断时调用,如来电。此时 touchesEnded:withEvent: 不会被调用。 |
以下是 touchesBegan:withEvent: 方法的示例代码:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSUInteger numTaps = [[touches anyObject] tapCount];
NSUInteger numTouches = [touches count];
// Do something here.
}
在这个方法中,可以通过 touches 集合获取当前屏幕上的手指数量,通过 UITouch 对象获取点击次数。还可以从 event 中获取特定视图内的触摸子集:
NSSet *myTouches = [event touchesForView:self.view];
通过 UITouch 对象可以获取手指在屏幕上的位置,并将其转换为视图的本地坐标系:
CGPoint point = [touch locationInView:self];
五、TouchExplorer应用程序
为了更好地理解四个触摸相关的响应方法何时被调用,我们可以创建一个 TouchExplorer 应用程序。
1. 创建项目
在Xcode中,使用单视图应用程序模板创建一个新项目,产品名称为 TouchExplorer ,设备系列选择iPhone。
2. 界面设计
该应用程序需要三个标签:一个用于指示最后调用的方法,另一个用于报告当前点击次数,第三个用于报告触摸次数。
- 在 BIDViewController.h 中添加三个出口和一个方法声明:
#import <UIKit/UIKit.h>
@interface BIDViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
@property (weak, nonatomic) IBOutlet UILabel *tapsLabel;
@property (weak, nonatomic) IBOutlet UILabel *touchesLabel;
- (void)updateLabelsFromTouches:(NSSet *)touches;
@end
- 打开
BIDViewController.xib文件:- 拖动一个标签到视图上,使用蓝色指南将其放置在视图的左上角。
- 使用调整大小手柄将标签调整到右侧的蓝色指南。
- 使用属性检查器将标签对齐方式设置为居中。
- 按住Option键拖动另外两个标签,使它们一个在另一个下方排列。
- 从“文件所有者”图标控制拖动到三个标签,分别连接到
messageLabel、tapsLabel和touchesLabel出口。 - 清除标签中的文本。
- 确保视图的“用户交互启用”和“多点触摸”选项被选中。
3. 代码实现
在 BIDViewController.m 文件中添加以下代码:
#import "BIDViewController.h"
@implementation BIDViewController
@synthesize messageLabel;
@synthesize tapsLabel;
@synthesize touchesLabel;
- (void)updateLabelsFromTouches:(NSSet *)touches {
NSUInteger numTaps = [[touches anyObject] tapCount];
NSString *tapsMessage = [[NSString alloc]
initWithFormat:@"%d taps detected", numTaps];
tapsLabel.text = tapsMessage;
NSUInteger numTouches = [touches count];
NSString *touchMsg = [[NSString alloc] initWithFormat:
@"%d touches detected", numTouches];
touchesLabel.text = touchMsg;
}
- (void)viewDidUnload {
[super viewDidUnload];
self.messageLabel = nil;
self.tapsLabel = nil;
self.touchesLabel = nil;
}
#pragma mark -
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
messageLabel.text = @"Touches Began";
[self updateLabelsFromTouches:touches];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
messageLabel.text = @"Touches Cancelled";
[self updateLabelsFromTouches:touches];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
messageLabel.text = @"Touches Ended.";
[self updateLabelsFromTouches:touches];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
messageLabel.text = @"Drag Detected";
[self updateLabelsFromTouches:touches];
}
@end
4. 编译和运行
编译并运行应用程序。在模拟器中,可以通过多次点击屏幕来增加点击次数,点击并按住鼠标拖动来模拟触摸和拖动。还可以通过按住Option键点击并拖动鼠标来模拟两指捏合,按住Option键和Shift键模拟两指滑动。
通过以上步骤,我们可以看到四个触摸相关方法在不同操作下的调用情况,加深对iOS设备手势处理的理解。
六、常见手势操作及模拟
iOS设备丰富的手势操作极大地提升了用户体验,在模拟器中也能模拟部分手势来测试应用的响应。以下详细介绍常见手势及其在模拟器中的模拟方式:
| 手势类型 | 实际操作 | 模拟器模拟方法 |
|---|---|---|
| 单点击 | 手指轻触屏幕后立即抬起 | 鼠标点击屏幕 |
| 多次点击 | 快速连续点击屏幕增加点击次数 | 多次快速点击鼠标 |
| 触摸拖动 | 手指触摸屏幕并移动 | 点击鼠标并按住,然后拖动鼠标 |
| 两指捏合 | 两根手指在屏幕上做捏合动作以缩放 | 按住Option键,点击鼠标并拖动 |
| 两指滑动 | 两根手指在屏幕上同向滑动 | 先按住Option键模拟捏合,移动鼠标使两个虚拟手指点相邻,再按住Shift键并移动鼠标 |
七、手势处理的注意事项
在处理手势时,有一些重要的注意事项需要牢记,以确保应用程序的稳定性和用户体验:
1. 事件转发
当一个响应者不处理某个事件时,必须手动将事件转发给响应链中的下一个对象,否则可能会导致其他视图无法识别手势。例如,在自定义的表格视图单元格中,如果只处理特定的手势,对于其他手势需要进行正确的转发:
-(void)respondToFictionalEvent:(UIEvent *)event {
if (someCondition)
[self handleEvent:event];
else
[self.nextResponder respondToFictionalEvent:event];
}
2. 多点触摸设置
在视图的属性设置中,要确保“用户交互启用”和“多点触摸”选项被选中,否则控制器类的触摸方法可能只能接收到一个触摸事件,无法正确处理多点触摸的情况。操作步骤如下:
1. 打开Interface Builder,找到对应的视图。
2. 调出属性检查器。
3. 在视图部分,勾选“用户交互启用”和“多点触摸”。
3. 中断处理
当用户在手势进行中被中断(如来电), touchesCancelled:withEvent: 方法会被调用。在这个方法中,需要进行必要的清理工作,以便能够重新开始新的手势。同时,此时 touchesEnded:withEvent: 方法不会被调用。
八、手势处理的实际应用场景
手势处理在iOS应用开发中有广泛的实际应用场景,以下是一些常见的例子:
1. 邮件应用
在邮件应用中,手势可以提供便捷的操作方式:
- 滑动删除 :用户在邮件列表中滑动某封邮件,会出现删除按钮,点击即可删除该邮件。
- 批量删除 :用户点击编辑按钮,勾选多封邮件后点击删除按钮,可批量删除邮件。
2. 图片浏览应用
在图片浏览应用中,手势可以实现缩放、切换等功能:
- 两指捏合缩放 :用户通过两指捏合或反向捏合来缩小或放大图片。
- 滑动切换图片 :用户在图片上左右滑动可以切换到上一张或下一张图片。
3. 应用管理
在主屏幕上,用户可以通过长按应用图标进入“抖动模式”,此时可以删除应用或进行重新排列。
九、总结
通过对iOS绘图和手势处理的学习,我们了解了从Quartz绘图切换到OpenGL ES绘图的具体步骤,包括更新视图控制器、Nib文件以及链接必要的框架。同时,深入掌握了iOS设备的手势处理机制,包括多点触控术语、响应链、触摸通知方法等。
在实际开发中,我们可以根据具体需求选择合适的手势处理方式,将手势处理代码嵌入到视图类或视图控制器类中。通过创建 TouchExplorer 应用程序,我们可以直观地观察四个触摸相关方法的调用情况,加深对iOS手势处理的理解。
此外,我们还学习了在模拟器中模拟常见手势的方法,以及手势处理的注意事项和实际应用场景。这些知识将帮助我们开发出更加友好、易用的iOS应用程序,提升用户体验。
在未来的开发中,随着技术的不断发展,iOS设备的手势处理功能可能会更加丰富和强大。我们可以进一步探索和应用新的手势,为用户带来更多惊喜和便利。
graph LR
A[开始] --> B[创建项目]
B --> C[界面设计]
C --> D[代码实现]
D --> E[编译运行]
E --> F[测试手势]
F --> G[优化调整]
G --> H[完成应用]
通过以上的流程,我们可以逐步开发出一个具备完善手势处理功能的iOS应用程序。在每个步骤中,都要严格按照相关的操作要求进行,确保应用的质量和稳定性。希望这些知识对大家在iOS开发中有所帮助,让我们能够更好地利用iOS设备的特性,创造出优秀的应用作品。
超级会员免费看

51

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



