iOS开发之触摸事件以及手势
iOS中的事件分为三类:触摸事件、加速计事件、远程控制事件。只有继承了UIResponder的对象才能接收并处理事件,称之为“响应者对象”。UIApplication、UIViewController、UIView都继承自UIResponder。UIResponder内部提供的方法来处理事件:
触摸事件:touchesBegan、touchesMoved、touchesEnded、touchesCancelled
加速计事件:motionBegan、motionEnded、motionCancelled
远程控制事件:remoteControlReceivedWithEvent
UIVeiw的触摸事件处理过程:
/**
*当手指开始触摸view时调用
*
*@paramtouches<#touchesdescription#>
*@paramevent<#eventdescription#>
*/
-(void)touchesBegan:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event{
NSLog(@"%s",__func__);
}
/**
*当手指在view上移动时调用
*
*@paramtouches<#touchesdescription#>
*@paramevent<#eventdescription#>
*/
-(void)touchesMoved:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event{
NSLog(@"%s",__func__);
}
/**
*当手指离开view时调用
*
*@paramtouches<#touchesdescription#>
*@paramevent<#eventdescription#>
*/
-(void)touchesEnded:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event{
NSLog(@"%s",__func__);
}
/**
*当触摸事件被系统事件打断时调用
*
*@paramtouches<#touchesdescription#>
*@paramevent<#eventdescription#>
*/
-(void)touchesCancelled:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event{
NSLog(@"%s",__func__);
}
一次触摸动作必然会调用touchesBeagn、touchesMoved和touchesEnded这三个方法。
说到这几个触摸方法,首先要知道UITouch这个对象。当一根手指触摸屏幕时就会产生一个与之关联的UITouch对象,一根手指对应一个UITouch对象。这个对象里面保存着这次触摸的信息,比如触摸的位置,时间,阶段等,当手指移动时,系统会更新同一个UITouch对象。使其能一直保存该手指所在的触摸位置信息。当手指离开屏幕时,系统会销毁对应的UITouch对象。
@interfaceUITouch:NSObject @property(nonatomic,readonly)NSTimeIntervaltimestamp; @property(nonatomic,readonly)UITouchPhasephase; @property(nonatomic,readonly)NSUIntegertapCount;//touchdownwithinacertainpointwithinacertainamountoftime //majorRadiusandmajorRadiusToleranceareinpoints //ThemajorRadiuswillbeaccurate+/-themajorRadiusTolerance @property(nonatomic,readonly)CGFloatmajorRadiusNS_AVAILABLE_IOS(8_0); @property(nonatomic,readonly)CGFloatmajorRadiusToleranceNS_AVAILABLE_IOS(8_0); @property(nullable,nonatomic,readonly,strong)UIWindow*window; @property(nullable,nonatomic,readonly,strong)UIView*view; @property(nullable,nonatomic,readonly,copy)NSArray<UIGestureRecognizer*>*gestureRecognizersNS_AVAILABLE_IOS(3_2); //获取当前位置 -(CGPoint)locationInView:(nullableUIView*)view; //获取上一个触摸点的位置 -(CGPoint)previousLocationInView:(nullableUIView*)view; //Forceofthetouch,where1.0representstheforceofanaveragetouch @property(nonatomic,readonly)CGFloatforceNS_AVAILABLE_IOS(9_0); //Maximumpossibleforcewiththisinputmechanism @property(nonatomic,readonly)CGFloatmaximumPossibleForceNS_AVAILABLE_IOS(9_0); @end
eg:让一个view随着手指的移动而移动
/**
*当手指在view上移动时调用
*
*@paramtouches<#touchesdescription#>
*@paramevent<#eventdescription#>
*/
-(void)touchesMoved:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event{
NSLog(@"%s",__func__);
//获取UITouch对象
UITouch*touch=[touchesanyObject];
//获取当前点的位置
CGPointcurP=[touchlocationInView:self];
//获取上一个点的位置
CGPointpreP=[touchpreviousLocationInView:self];
//计算x的偏移量
CGFloatoffsetX=curP.x-preP.x;
//计算y的偏移量
CGFloatoffsetY=curP.y=preP.y;
//修改view的位置
self.transform=CGAffineTransformTranslate(self.transform,offsetX,offsetY);
}
就是根据UITouch对象中保存的位置信息来实现的。
事件的产生和传递:
当触摸事件产生后,系统会将该事件添加到一个由UIApplication管理的事件队列中去。UIApplication会从队列中取出最前面的事件,发送给应用程序的主窗口的处理。主窗口会在视图层次结构中,找一个最合适的视图并调用touches方法来处理触摸事件。触摸事件的传递是从父控件传递到子控件。如果父控件不能接收到触摸事件,那么子控件就不可能接收到触摸事件。
如何找到最合适的控件来处理事件?首先判断自己是否能接收触摸事件?触摸点是否在自己身上?从后往前遍历子控件,重复之前的两个步骤,如果没有符合条件的子控件,那么就自己最合适处理。
控件用hitTest:withEvent:方法来寻找最合适的view,用pointInside这个方法判断这个点在不在方法调用者即控件身上。
hitTest方法的底层实现:
-(UIView*)hitTest:(CGPoint)pointwithEvent:(UIEvent*)event{
//判断当前控件是否能接收触摸事件
if(self.userInteractionEnabled==NO||self.hidden==YES||self.alpha<=0.01){
returnnil;
}
//判断触摸点是否在当前控件上
if([selfpointInside:pointwithEvent:event]==NO){
returnnil;
}
//从后往前遍历自己的子控件
NSIntegercount=self.subviews.count;
for(NSIntegeri=count-1;i>=0;i--){
UIView*childView=self.subviews[i];
//把当前控件上的坐标系转换成子控件上的坐标系
CGPointchildPoint=[selfconvertPoint:pointtoView:childView];
//递归调用hitTest方法寻找最合适的view
UIView*fitView=[childViewhitTest:childPointwithEvent:event];
if(fitView){
returnfitView;
}
}
//循环结束,没有比自己更合适的view,返回自己
returnself;
}
然而使用touches方法监听触摸事件是有缺点的,比如要自定义view,所以iOS3.2之后苹果推出了手势识别功能UIGestureRecognizer。UIGestureRecognizer是一个抽象类,它的子类才能处理具体的某个手势。
具体有以下几种手势:
//点按手势 //UITapGestureRecognizer*tap=[UITapGestureRecognizeralloc]initWithTarget:<#(nullableid)#>action:<#(nullableSEL)#> //长按手势默认是触发两次 //UILongPressGestureRecognizer*longP=[UILongPressGestureRecognizeralloc]initWithTarget:<#(nullableid)#>action:<#(nullableSEL)#> //轻扫手势默认方向是往右 //UISwipeGestureRecognizer*swipe=[UISwipeGestureRecognizeralloc]initWithTarget:<#(nullableid)#>action:<#(nullableSEL)#> //旋转手势 //UIRotationGestureRecognizer*rotation=[UIRotationGestureRecognizeralloc]initWithTarget:<#(nullableid)#>action:<#(nullableSEL)#> //捏合手势 //UIPinchGestureRecognizer*pinch=[UIPinchGestureRecognizeralloc]initWithTarget:<#(nullableid)#>action:<#(nullableSEL)#> //拖拽手势 //UIPanGestureRecognizer*pan=[UIPanGestureRecognizeralloc]initWithTarget:<#(nullableid)#>action:<#(nullableSEL)#>
实际运用:
@interfaceViewController()<UIGestureRecognizerDelegate>
@property(weak,nonatomic)IBOutletUIImageView*imageView;
@end
@implementationViewController
-(void)viewDidLoad{
[superviewDidLoad];
[selfsetUpPinch];
[selfsetUpRotation];
[selfsetUpPan];
}
#pragmamark-手势代理方法
//是否允许开始触发手势
//-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer
//{
//returnNO;
//}
//是否允许同时支持多个手势,默认是不支持多个手势
//返回yes表示支持多个手势
-(BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizershouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
{
returnYES;
}
//是否允许接收手指的触摸点
//-(BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizershouldReceiveTouch:(UITouch*)touch{
////获取当前的触摸点
//CGPointcurP=[touchlocationInView:self.imageView];
//
//if(curP.x<self.imageView.bounds.size.width*0.5){
//returnNO;
//}else{
//returnYES;
//}
//}
#pragmamark-点按手势
-(void)setUpTap
{
//创建点按手势
UITapGestureRecognizer*tap=[[UITapGestureRecognizeralloc]initWithTarget:selfaction:@selector(tap:)];
tap.delegate=self;
[_imageViewaddGestureRecognizer:tap];
}
-(void)tap:(UITapGestureRecognizer*)tap
{
NSLog(@"%s",__func__);
}
#pragmamark-长按手势
//默认会触发两次
-(void)setUpLongPress
{
UILongPressGestureRecognizer*longPress=[[UILongPressGestureRecognizeralloc]initWithTarget:selfaction:@selector(longPress:)];
[self.imageViewaddGestureRecognizer:longPress];
}
-(void)longPress:(UILongPressGestureRecognizer*)longPress
{
if(longPress.state==UIGestureRecognizerStateBegan){
NSLog(@"%s",__func__);
}
}
#pragmamark-轻扫
-(void)setUpSwipe
{
//默认轻扫的方向是往右
UISwipeGestureRecognizer*swipe=[[UISwipeGestureRecognizeralloc]initWithTarget:selfaction:@selector(swipe)];
swipe.direction=UISwipeGestureRecognizerDirectionUp;
[self.imageViewaddGestureRecognizer:swipe];
//如果以后想要一个控件支持多个方向的轻扫,必须创建多个轻扫手势,一个轻扫手势只支持一个方向
//默认轻扫的方向是往右
UISwipeGestureRecognizer*swipeDown=[[UISwipeGestureRecognizeralloc]initWithTarget:selfaction:@selector(swipe)];
swipeDown.direction=UISwipeGestureRecognizerDirectionDown;
[self.imageViewaddGestureRecognizer:swipeDown];
}
-(void)swipe
{
NSLog(@"%s",__func__);
}
#pragmamark-旋转手势
-(void)setUpRotation
{
UIRotationGestureRecognizer*rotation=[[UIRotationGestureRecognizeralloc]initWithTarget:selfaction:@selector(rotation:)];
rotation.delegate=self;
[self.imageViewaddGestureRecognizer:rotation];
}
//默认传递的旋转的角度都是相对于最开始的位置
-(void)rotation:(UIRotationGestureRecognizer*)rotation
{
self.imageView.transform=CGAffineTransformRotate(self.imageView.transform,rotation.rotation);
//复位
rotation.rotation=0;
//获取手势旋转的角度
NSLog(@"%f",rotation.rotation);
}
#pragmamark-捏合
-(void)setUpPinch
{
UIPinchGestureRecognizer*pinch=[[UIPinchGestureRecognizeralloc]initWithTarget:selfaction:@selector(pinch:)];
pinch.delegate=self;
[self.imageViewaddGestureRecognizer:pinch];
}
-(void)pinch:(UIPinchGestureRecognizer*)pinch
{
self.imageView.transform=CGAffineTransformScale(self.imageView.transform,pinch.scale,pinch.scale);
//复位
pinch.scale=1;
}
#pragmamark-拖拽
-(void)setUpPan
{
UIPanGestureRecognizer*pan=[[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(pan:)];
[self.imageViewaddGestureRecognizer:pan];
}
-(void)pan:(UIPanGestureRecognizer*)pan
{
//获取手势的触摸点
//CGPointcurP=[panlocationInView:self.imageView];
//移动视图
//获取手势的移动,也是相对于最开始的位置
CGPointtransP=[pantranslationInView:self.imageView];
self.imageView.transform=CGAffineTransformTranslate(self.imageView.transform,transP.x,transP.y);
//复位
[pansetTranslation:CGPointZeroinView:self.imageView];
//NSLog(@"%@",NSStringFromCGPoint(curP));
}
@end
以上就是iOS触摸事件以及手势的相关内容介绍,希望对大家学习iOS程序设计有所帮助。