iphone的Touch事件
花了点时间整理了一下关于Touch事件的一些方法。
轻击:
需要在你的ViewController里重写几个方法:
//开始触摸的方法
- (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 Stopped.";//触摸结束的方法
[self updateLabelsFromTouches:touches];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
messageLabel.text = @"Drag Detected";//触摸移动的方法
[self updateLabelsFromTouches:touches];
}
触摸-清扫:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
gestureStartPoint = [touch locationInView:self.view];//开始触摸
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self.view];
CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x);
CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y);
if (deltaX >= kMinimumGestureLength && deltaY <= kMaximumVariance) {
label.text = @"Horizontal swipe detected";//水平消除
[self performSelector:@selector(eraseText)
withObject:nil afterDelay:2];
}
else if (deltaY >= kMinimumGestureLength &&
deltaX <= kMaximumVariance){
label.text = @"Vertical swipe detected";//垂直消除
[self performSelector:@selector(eraseText) withObject:nil
afterDelay:2];
}
//kMinimumGestureLength 最小移动长度 kMaximumVariance 最大偏移长度
}
多次轻击判断,比如双击,三击等:
- (void)singleTap {
singleLabel.text = @"Single Tap Detected";//单击动作响应事件
[self performSelector:@selector(eraseMe:)
withObject:singleLabel afterDelay:1.6f];//1.6秒后执行eraseMe方法
}
- (void)doubleTap {
doubleLabel.text = @"Double Tap Detected";//双击
[self performSelector:@selector(eraseMe:)
withObject:doubleLabel afterDelay:1.6f];
}
- (void)tripleTap {
tripleLabel.text = @"Triple Tap Detected";//三击
[self performSelector:@selector(eraseMe:)
withObject:tripleLabel afterDelay:1.6f];
}
- (void)quadrupleTap {
quadrupleLabel.text = @"Quadruple Tap Detected";//四击
[self performSelector:@selector(eraseMe:)
withObject:quadrupleLabel afterDelay:1.6f];
}
- (void)eraseMe:(UITextField *)textField {
textField.text = @"";
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];//实例一个uitouch
NSUInteger tapCount = [touch tapCount]; //计算touch的tapCount次数
switch (tapCount) {
case 1:
[self singleTap];
break;
case 2:
[self doubleTap];
break;
case 3:
[self tripleTap];
break;
case 4:
[self quadrupleTap];
break;
default:
break;
}
}
[self performSelector:@selector(eraseMe:)withObject:singleLabel afterDelay:1.6f]中
performSelector:@selector(eraseMe:)withObject:singleLabel afterDelay:1.6f方法为将来afterDelay1.6秒之后调用eraseMe方法
同样的[NSObect cancelPreviousPerformSelector:withObject :afterDelay:];
方法为取消这些将来的调用
捏合操作:
- (void)eraseLabel {//清空lable
label.text = @"";
}
- (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) {//检测是否大于最小移动值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;
}
自定义手势“√”:
- (void)eraseLabel {
label.text = @"";
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self.view];
lastPreviousPoint = point;
lastCurrentPoint = point;
lineLengthSoFar = 0.0f;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint previousPoint = [touch previousLocationInView:self.view];
CGPoint currentPoint = [touch locationInView:self.view];
CGFloat angle = angleBetweenLines(lastPreviousPoint, //计算两条线之间的角度
lastCurrentPoint,
previousPoint,
currentPoint);
if (angle >= kMinimumCheckMarkAngle&& angle <= kMaximumCheckMarkAngle
&& lineLengthSoFar > kMinimumCheckMarkLength) {//检测手势被承认的条件 kMinimumCheckMarkAngle 最小角度kMaximumCheckMarkAngle最大角度kMinimumCheckMarkLength 画线最小长度
label.text = @"Checkmark";
[self performSelector:@selector(eraseLabel)
withObject:nil afterDelay:1.6];
}
lineLengthSoFar += distanceBetweenPoints(previousPoint, currentPoint);//lineLengthSoFar , lastPreviousPoint, lastCurrentPoint 重新赋值
lastPreviousPoint = previousPoint;
lastCurrentPoint = currentPoint;
}
这里用到一个判断两条直线的角度的方法 angleBetweenLines(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPointlin2End);
给一个几何方法集的接口方法:
CGPointUtils.h 头文件
#import <CoreGraphics/CoreGraphics.h>
CGFloat distanceBetweenPoints (CGPoint first, CGPoint second);
CGFloat angleBetweenPoints(CGPoint first, CGPoint second);
CGFloat angleBetweenLines(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint lin2End);
.c文件 CGPointUtils.c
#include "CGPointUtils.h"
#include <math.h>
#define pi 3.14159265358979323846
#define degreesToRadian(x) (pi * x / 180.0)
#define radiansToDegrees(x) (180.0 * x / pi)
CGFloat distanceBetweenPoints (CGPoint first, CGPoint second) {
CGFloat deltaX = second.x - first.x;
CGFloat deltaY = second.y - first.y;
return sqrt(deltaX*deltaX + deltaY*deltaY );
};
CGFloat angleBetweenPoints(CGPoint first, CGPoint second) {
CGFloat height = second.y - first.y;
CGFloat width = first.x - second.x;
CGFloat rads = atan(height/width);
return radiansToDegrees(rads);
//degs = degrees(atan((top - bottom)/(right - left)))
}
CGFloat angleBetweenLines(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End) {
CGFloat a = line1End.x - line1Start.x;
CGFloat b = line1End.y - line1Start.y;
CGFloat c = line2End.x - line2Start.x;
CGFloat d = line2End.y - line2Start.y;
CGFloat rads = acos(((a*c) + (b*d)) / ((sqrt(a*a + b*b)) * (sqrt(c*c + d*d))));
return radiansToDegrees(rads);
}
把他加到工程里 在需要的地方#import "CGPointUtils.h" 就可以直接用了
iphone 里如果截获UIEvent事件?1,可以重载UIApplication 或 UIWindow 的SendEvent ,然后在其中做些操作。重载后如何使用见int main(int argc, char *argv[]){ NSString* appClass = @"MyUI"; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int retVal = UIApplicationMain(argc, argv, appClass, nil); [pool release]; return retVal;}其实就是设置UIApplicationMain的第三个参数。2,如何简单的截获事件还不能满足你的要求,比如你有时需要在touchEnd的时候才能确定是否要没收该事件,即不调用[super sendEvent:event] 。 那么 touchBegain时你不能马上调用 [super sendEvent:event] ,而是希望缓存该UIEvent ,最后在touchEnd的时候确实是否需要没收。如果不没收该事件,则先调用之前缓存的 touchBegain Event ,在调用touchEnd事件。这里有个问题,如何缓存UIEvent??eventhandlingiphon 文档中提示千万不要retain UIEvent,你只可以拷贝其中的信息。其实UIEvent 对象是复用的,比如touch 事件,只是其中的UITouch对象的值不同。关键是UIEvent,UITouch的许多属性都是 readonly ,你修改不了。所以你自己alloc UIEvent也没用。幸好,objective-C有个 类别(category) ,这样你可以为UIEvent ,UITouch添加 method ,然后在这些method 中 就可以访问私有的 数据成员了。所以 发展可以这样后 很奇怪,那相当于你所有的 私有成员都公开了,这还是oo吗??几个有用连接如下UITouch *touch = [[[UITouch alloc] init] autorelease];NSSet *touches = [NSSet setWithObject:touch];UIEvent *event = [[[UIEvent alloc] init] autorelease];[view touchesBegan:touches withEvent:event];[view touchesEnded:touches withEvent:event];So all we have to do is create the UITouch and UIEvent objects that the functions expect to see, and all will be well, right? Except that Apple didn’t provide initializers for these objects. And they have private fields that have to be set up just so, or your app will crash@interface UITouch (Synthesize)- (id)initInView:(UIView *)view;- (void)setPhase:(UITouchPhase)phase;- (void)setLocationInWindow:(CGPoint)location;- (void)moveLocationInWindow;@endIn Ruby, you’d write a monkey patch, modifying the vendor’s class at runtime. Objective-C o!ers a slightly more civilized take on the concept, called a category. You can add methods to a third-party class, and spell out the scope in which they apply. Your new methods have access to the class’s private fields; lucky for would-be GUI testers