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程序设计有所帮助。