IPhone的成功,其支持多点触摸的电容屏触摸技术有不小的功劳,最近进行地图软件的移植开发,对多点触控进行了一些研究,在这里整理一下开发心得同大家分享。
老的电阻式触摸屏(就是不支持多点触摸,需要用触控笔操作的),相对于鼠标的使用行为,其实差别不大,所以在windows消息里面,对触控消息,都还是沿用老的mousedown,mouseup,mousemove这三个函数处理,唯一和鼠标不一样的,就是
1. 没有鼠标左键右键的区分
2. 只要有mousemove消息,肯定先有mousedown,触摸屏上移动肯定要先点击了
但是总体而言,单点触摸屏的消息机制同鼠标差别不大,每个事件只有一个坐标。
不过多点触摸就完全不一样了,同时要跟踪多个坐标变化,老的down up move消息模型不完全适用这种情况,必须要使用新的消息机制。
下面我们来看IOS使用的消息模型,如下:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
这里的Began Ended Moved, 咋一看同老的down up move消息模型差不多,不过理念上还是有很大不同。最基本的不同,就是传入的是多个触摸对象。
有了多个对象带来一个问题,时刻一检测到设备上A点,B点有触摸信号,时刻二检测到C点,D点有触摸信号,那么,是按住A点的手指运动到了C点,按住B点的手指运动到了D点,还是A到D,B到C呢?抑或是A到C,但是B点的手指抬起来,同时另一个手指按住了D? 乍一想,大家可能觉得运动是连续性的,可以判断呀,但是,连续性是理论上及哲学上的一个概念,物理设备的检测不存在连续性,(可以做一个实验,windows下响应mousemove消息,每响应一次就在坐标上画一个点,在快速移动鼠标的情况下,点是很离散的)我们只有通过各种算法推断两个时间段上触控对象的联系。
在鼠标及单点触摸屏处理上,整个屏幕响应的点永远只有一个,因此老的所有鼠标事件,传入的参数只有坐标及其它一些状态值,而不会传入一个鼠标对象,那么对于多点触控,是不是只传入多个坐标点就可以了? 答案是,不行,如上所说,多点触控,实际上有了多个触控对象,我们需要跟踪这些对象.
苹果的touch消息接口通过 touches 对象封装了一个触摸操作, 一个touches对象对应一个点的触摸操作, 多个点同时被按下就有多个touches对象, 注意我强调了同时, 如果两个指头是先后按住屏幕的, 会收到两个touchesBegan消息, 这很好理解, 但是此时要注意, 第二次touchesBegan 发生时, 屏幕这时有两个点被按住, 但是touchesBegan 传入的touches 集合只有一个touch成员.
同样, 手指在屏幕移动时, 如果两个手指都按住屏幕, 但是只有一个手指移动, 另一个按着不动, touchesMoved 同样也只传入一个touch对象, 所以一定要注意,依靠touch事件中的(NSSet *)touches 参数个数判断是单点还是多点触摸, 是不可靠的
在很流行的iphone入门开发书籍《Iphone3 开发基础教程》中关于多点触摸的例程 PinchMe, 就使用touches 的个数来判断两点缩放操作,这是不严谨的
//
// PinchMeViewController.m
// PinchMe
//
// Created by jeff on 4/28/09.
// Copyright Jeff LaMarche 2009. All rights reserved.
//
#import "PinchMeViewController.h"
#import "CGPointUtils.h"
@implementation PinchMeViewController
@synthesize label;
@synthesize initialDistance;
- (void)eraseLabel {
label.text = @"";
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.label = nil;
}
- (void)dealloc {
[label release];
[super dealloc];
}
#pragma mark -
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if([touches count] == 2){
NSArray *twoTouches = [touches allObjects];
UITouch *first = [twoTouches objectAtIndex:0];
UITouch *second = [twoTouches objectAtIndex:1];
initialDistance = distanceBetweenPoints(
[first locationInView:self.view],
[second locationInView:self.view]);
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if([touches count] == 2) {
NSArray *twoTouches = [touches allObjects];
UITouch *first = [twoTouches objectAtIndex:0];
UITouch *second = [twoTouches objectAtIndex:1];
CGFloat currentDistance = distanceBetweenPoints(
[first locationInView:self.view],
[second locationInView:self.view]);
if (initialDistance == 0)
initialDistance = currentDistance;
else if (currentDistance - initialDistance > kMinimumPinchDelta) {
label.text = @"Outward Pinch";
[self performSelector:@selector(eraseLabel)
withObject:nil
afterDelay:1.6f];
}
else if (initialDistance - currentDistance > kMinimumPinchDelta) {
label.text = @"Inward Pinch";
[self performSelector:@selector(eraseLabel)
withObject:nil
afterDelay:1.6f];
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
initialDistance = 0;
}
@end
把它的例子编译到设备上面,你会发现,如果两个手指不是同时落到屏幕,或是滑动手指时保持一个手指不动,缩放操作是无效的。
如果是我设计这个接口,我可能会考虑不管屏幕触控对象有没有移动,我都会吧所有按下的触摸对象传入函数,然后设计一个标志位标识哪些对象是活动的,哪些对象不活动。
不过既然苹果没有按照这个设想设计接口,也有解决方法,就是我们自己保存touch队列来管理触摸对象。
我们可以在负责按下消息的 touchesBegan 函数中,存储传入的touches 对象到我们自己的touch队列,在touchesEnded 时,在这个队列中删除传入的touches对象, 在touchesMoved中,以我们自己维护的touch队列成员个数来判断当前是否按下多点,而不是依靠传入的 touches对象,
代码如下:
TouchRecord 是我们自定义的touch对象
@interface TouchRecord : NSObject
{
id m_id; //用以唯一标识touch对象,实际他是传入的touches集合中touch对象的指针
CGPoint m_point; // touch对象的位置
}
@synthesize m_point;
@synthesize m_phase;
{
return [self initWithTouch:nil pointInView:CGPointMake(0.0, 0.0)];
}
- (id)initWithTouch:(UITouch*)aTouch pointInView:(CGPoint)point
{
self = [super init];
if (self) {
/* class-specific initialization goes here */
m_id = aTouch;
m_point = point;
m_phase = aTouch.phase;
}
return self;
}
[super dealloc];
}
{
for (UITouch* touch in touches) {
CGPoint point = [touch locationInView:self];
TouchRecord* record = [[TouchRecord alloc] initWithTouch:touch pointInView:point];
[m_arrayTouch addObject:record];
[record release];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch* touch in touches) {
CGPoint point = [touch locationInView:self];
for (TouchRecord* record in m_arrayTouch) {
if (touch == record.m_id) {
record.m_point = point;
record.m_phase = touch.phase;
break;
}
}
}
}
// Handles the end of a touch event.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch* touch in touches) {
for (TouchRecord* record in m_arrayTouch) {
if (touch == record.m_id) {
[m_arrayTouch removeObject:record];
break;
}
}
}
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch* touch in touches) {
for (TouchRecord* record in m_arrayTouch) {
if (touch == record.m_id) {
[m_arrayTouch removeObject:record];
break;
}
}
}
}
UITouchPhasem_phase; //touch对象的状态
@implementation TouchRecord
@synthesize m_id;
- (id)init
- (void)dealloc {
@end
//touch事件
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
// Handles the continuation of a touch.
m_arrayTouch在view中定义为NSMutableArray* m_arrayTouch;使我们自己维护的touch集合,成员是TouchRecord 对象
通过这种管理方式,我们就能够正确判断当前的多点触摸状态。
在 IOS 3.2 SDK后,苹果提供了手势消息 UIGestureRecognizer, 可以对常用的两点缩放,旋转,轻扫等手势直接封装成对应的消息,有兴趣的读者可以查阅相关资料。这简化了手势操作的编程,大家可以不同began move这类消息直接打交道,但是仅支持 IOS3.2以上系统, 3.2看起来不算新,但要知道 对于一些古老设备(比如itouch 1代),最高只能升级到 IOS 3.1.2系统的,同时这类消息也有局限性,在多点触摸时代,程序中经常需要自定义一些动作,所以掌握自己管理touch对象方法也是非常必要的。
最后,大家通过编写测试代码,可很容易测得, Iphone,itouch上,最多可支持5点触摸。而在Ipad上呢, 最多可支持11个点的触摸
至于现在使用到11个点的应用,大家可去试试钢琴类的应用程序,同时按下11个音,第12个就按不出来了。
----
转自:iphone多点触摸机制及开发需注意的问题
分享到:
相关推荐
处理多点触摸时,需要注意性能问题。过多的触摸事件处理可能导致CPU占用过高,影响用户体验。优化策略包括合理地使用手势识别器,避免不必要的计算,以及在不需要处理触摸事件时调用`super.touchesXXX(_:with:)`以...
在iOS开发中,多点触控(Multitouch)是一项重要的功能,允许用户通过同时使用两个或更多个手指与屏幕进行交互。iPhone作为一款广泛使用的智能设备,其用户界面设计和交互体验很大程度上依赖于多点触控技术。本范例...
iOS设备的硬件特性,如多点触摸屏和加速度计,也为游戏开发提供了独特的机会。开发者需要学习如何响应用户的触摸事件和设备运动,以提供沉浸式的游戏体验。本书可能会详细解释如何利用Core Motion框架来获取和处理...
- **多点触控**:了解如何处理多点触摸事件,这是iPhone用户体验的核心之一。 - **运动事件**:掌握如何处理加速度计产生的运动事件。 - **拷贝和粘贴**:学习如何在应用程序中实现基本的文本编辑功能,如复制、粘贴...
5. Cocoa Touch:Cocoa Touch是iPhone SDK中专门用于触摸界面开发的部分。它提供了许多与多点触控、手势识别、动画等有关的类和API。掌握Cocoa Touch框架中的内容对于开发具有良好交互体验的应用程序至关重要。 6. ...
《深入浅出iPhone开发(中文版)》是针对iPhone应用开发的一本专业书籍,由丹皮洛内原著,鲁成东翻译。这本书旨在为读者提供一个全面、深入且易懂的iPhone开发学习路径,帮助开发者从零基础快速掌握iPhone应用程序的...
此指南特别强调了本地应用程序与基于Web的应用程序的区别,前者能够充分利用设备特性,如加速计、定位服务和多点触摸功能,并能与系统其他应用程序进行深度集成。 iPhone SDK为开发者提供了必要的工具和资源,包括...
- 自定义视图的方法及注意事项 - **第5章**:处理键盘输入 - 键盘类型的设置与调整 - 文本输入的管理 - 特殊按键事件的处理 - **第6章**:屏幕旋转处理 - 屏幕方向检测 - 不同方向下的视图更新策略 - 优化...
- **触摸交互**:掌握处理用户触摸事件的方法,包括多点触控等。 - **UI组件**:深入探讨常用的UI组件,如按钮、文本框、滑块等,并了解它们在iPad上的实现细节。 **3. **高级功能** - **多任务处理**:讲解如何在...
通过本文档的学习,我们了解了iPhone应用开发的基本流程、所需的技术栈以及一些关键的实践技巧。无论是对于初学者还是有一定经验的开发者来说,掌握这些知识点都将有助于提高开发效率,创作出更优秀的应用程序。随着...
12. **Multitouch Support**:针对iOS设备的多点触控特性,Cocos2d-iPhone提供了易于使用的事件处理机制,可以处理多个手指的触摸事件。 13. **Debugging Tools**:框架内嵌了调试工具,如性能分析器、内存泄漏检测...
- **事件处理**:涵盖多点触摸、运动事件处理及应用程序内的拷贝和粘贴操作。 - **图形和描画**:讲解iPhoneOS的图形架构,包括描画形状和图像以及动画使用。 - **文本和Web**:介绍文本支持和管理系统键盘的方法...
4. **Cocoa Touch层**:这是iOS应用开发的核心部分,提供了用户界面元素和触摸事件处理机制。Cocoa Touch层是面向开发者的顶层接口,它封装了其他较低层次的功能,并提供了高级的UI组件和APIs。 - **用户界面框架...
- **文档名称与目的**:“iPhone应用程序编程指南(中文版)”旨在为开发者提供一套全面的指南,帮助他们理解和掌握构建iPhone本地应用程序所需的技能与知识。 - **文档重要性**:这份指南对于初学者和经验丰富的...
- **事件处理**:包括触摸事件、运动事件以及如何处理多点触摸等。 - **图形和描画**:探讨如何使用UIKit或Quartz等工具进行图形处理。 - **文本和Web**:讨论文本处理、网页显示以及键盘管理等内容。 - **文件和...
在iOS开发中,使用iPhone SDK进行应用程序开发时,有时我们需要实现一些高级的用户交互功能,例如让用户自由地在屏幕上绘制连续、平滑的任意轨迹。这个主题“iPhone SDK开发 —— 无断点画任意轨迹”就是关于如何在...