iOS 第11章 触摸事件与手势

目标

    了解多点触摸术语

    理解响应者链

    体系结构

    多点触摸的基本应用

 

1、了解多点触摸术语

触摸事件

   指手指放到 iOS 设备屏幕上 从屏幕上拖动或抬起。

   iOS中触摸事件,基于多点触摸模型

   多点触摸序列 NSSet*touches

一个或多个和屏幕接触的手指,识别为多点触摸序列的一部分

从第一个手指碰到屏幕开始,直到最后一个手指离开屏幕结束

   注意:触摸不关心,触摸的时间;只关心触摸的手指数目;触摸次数;触摸的方向;  

 

Touch 是指手指放到屏幕上

   触摸数量(touch):等于手指的数量,能够跟踪用户所有的手指,最多11个

   点击(tap):手指触摸屏幕、立即离开,则触发轻击

   检测到多点触摸,轻击次数置为1-------tapCount

下图表示一次触摸事件:

包含完整触摸事件的多个状态:

   开始(Began)、移动(Moved)、结束(Ended)、取消(Cancelled)

 

手势

    手势:是为简化 触摸操作,推出的一组对象.手势是约定俗成的。

    如果使用 手势对象,就不需要在 Began Moved 等方法中写代码。

    手势指从用户用一个或多个手指接触屏幕时开始,直到手指离开屏幕为止所发生的所有事件。无论多长时间,只要你还有一个或多个手指在屏幕上,这个手势就存在。(除非来电话会中断该手势)

 

   手势通过一系列 事件 内在系统来传递。用户与设备屏幕交互时生成事件。事件包含与发生的一次或多次触摸相关的信息。

   每次接触屏幕,都要传递两个参数:

   UITouch:多个触摸手指(触摸的顺序、触摸的位置)

   UIEvent:一个事件

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

 

 

手势识别器

      是实现所有手势的对象;

    是一个 UIGestureRecognizer 子类的对象;

    观察用户操作,并识别用户何时做了预先设置好的几种手势;

    可以用于程序中任何视图中;

      不需要编写手势处理方法(touchesBegin:withEvent:…);

    可以识别如下手势:

1、拍击           UITapGestureRecognizer  (任意次数的拍击)   
                2、向里或向外捏   UIPinchGestureRecognizer (用于缩放)   
  

3、摇动或者拖拽   UIPanGestureRecognizer   
  

4、擦碰           UISwipeGestureRecognizer(以任意方向)   
  

5、旋转           UIRotationGestureRecognizer(手指朝相反方向移动)   
  6、长按          UILongPressGestureRecognizer  

 

 

2、理解响应者链

响应者链

    第一响应者是用户正在交互的对象(IB 中叫 FirstResponder)

    以UIResponder为超类的任何类可以成为响应者

    如果第一响应者不处理事件,事件会被发送到 “父(上级)响应者”

    事件最终会被发到UIApplication,如果它不处理事件,将会被丢弃

 

 

 

3、体系结构

处理流程

   当一个或多个手指触摸屏幕的时候发出发出:

      -(void)touchesBegin: (NSSet*)touches  withEvent: 消息

   当一个或多个手指在屏幕移动的时候发出:

      -(void)touchesMoved:withEvent: 消息

   当一个或多个手指离开屏幕的时候发出:

      -(void)touchesEnded:withEvent: 消息

   当触摸序列被电话呼入等事件取消的时候发出:

      -(void)touchesCancelled:withEvent:消息

 

任何视图组件,都继承了 UIResponder  类,都可以调用触摸事件方法

两个参数:

基础代码

UITouch*currentTouch = [touches anyObject];  //得到任意一个触摸对象

Int phaseState =  currentTouch.phase;                 //当前触摸事件的状态       

CGPointpopMoved = [currentTouch locationInView:self.view]; //得到当前触摸事件在当前视图中的位置

 

 

4、多点触摸的基本应用

检测单击或双击

    单击事件 + 多触击事件

      1.两个触摸事件发生的间隔时间很短

      2.也只有当它们和同一个 视图相关联时

    在 touchesEnded:withEvent: 触摸结束的时候,
      判断击打次数,使用UITouch的tapCount方法

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

{

    //得到手指个数

   NSInteger ntouchCount = [touches count];

   self.lblFingers.text = [NSString stringWithFormat:@" %i 根手指",ntouchCount];

   //得到点击次数

  self.lblTapCounts.text = [NSString stringWithFormat:@"%i 次点击 %f ",currentTouch.tapCount,currentTouch.timestamp];

}

 

//检查手指数目

-(void)checkTouches:(NSSet *)touches

{

   UITouch*currentTouch = [touches anyObject];

   //根据当前手势的不同阶段,打印不同的信息

   switch(currentTouch.phase){

       caseUITouchPhaseBegan:

       {

            //potBegin 开始点击的位置

            self.potBegin = [currentTouch locationInView:self.view];

       }

            break;

       caseUITouchPhaseMoved:{

                       

       }

            break;

       caseUITouchPhaseEnded:{

            self.lblEnd.text = @"触摸结束";

            [self performSelector:@selector(eraseLabel:) withObject:self.lblEnd afterDelay:0.6f];

       }

            break;

       caseUITouchPhaseCancelled:{

       

       }

            break;

           

       default:

            break;

   }

   

}

 

 

检测碰擦手势(Swipe)

*.h 文件中

//触摸的开始坐标

@property(nonatomic)CGPoint beginPoint;

 

//定义用户滑动最少多少像素算一个手势

#define kMinSwipLength 25

//定义滑动时,偏移最多多少像素的误差

#define kMaxVariance  6

 

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

   UITouch *currentTouch = [touches anyObject];

    //移动后的点

   CGPointpopMoved = [currentTouch locationInView:self.view];

   floatdeltaX = fabsf(self.potBegin.x - popMoved.x);

   floatdeltaY = fabsf(self.potBegin.y - popMoved.y);

   //判断滑动方向

   if((deltaX > kMinSwipLength)&&(deltaY< kMaxVariance)) {

          self.lblSwipe.text = @"水平移动";

         //调用当前类的方法

         [self performSelector:@selector(eraseLabel:) withObject:self.lblSwipe afterDelay:0.6f];

   }

   

  if((deltaY > kMinSwipLength)&&(deltaX< kMaxVariance)){

           self.lblSwipe.text=@"垂直移动";

          [self performSelector:@selector(eraseLabel:) withObject:self.lblSwipe afterDelay:0.6f];

   }

 

}

 

 

 

移动一个按钮:

单独新建一个类,继承 UIButton,重写手势方法

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    if (!dragEnable) {

        return;

    }

    UITouch *touch = [touches anyObject];

    beginPoint = [touch locationInView:self];

}

 

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

    if (!dragEnable) {

        return;

    }

    UITouch *touch = [touches anyObject];

    CGPoint nowPoint = [touch locationInView:self];

    float offsetX = nowPoint.x - beginPoint.x;

    float offsetY = nowPoint.y - beginPoint.y;

   

    self.center = CGPointMake(self.center.x+offsetX, self.center.y+offsetY);

}

 

 

 

 

使用手势识别器

1)创建手势实例。当创建手势时,指定一个回调方法,当手势开始,改变、或结束时,回调方法被调用。


2)添加到需要识别的View中。每个手势只对应一个View,当屏幕触摸在View的边界内时,如果手势和预定的一样,那就会回调方法。

     注意:一个手势只能对应一个View,但是一个View可以有多个手势。建议在真机上运行这些手势,模拟器操作不太方便。

 

 

使用擦碰识别器(UISwipeGestureRecognizer)

- (void)viewDidLoad

{

    [super viewDidLoad];

    //直接使用手势判断对象,确定手势并调用方法

   UISwipeGestureRecognizer*vertical = [[UISwipeGestureRecognizeralloc]initWithTarget:self action:@selector(reportYSwipe:)];

   //设置手势方向

   vertical.direction= UISwipeGestureRecognizerDirectionUp|UISwipeGestureRecognizerDirectionDown;

   //把手势添加到当前视图中

   [self.view addGestureRecognizer:vertical];

   

   //再添加一个手势

   UISwipeGestureRecognizer*horizontal = [[UISwipeGestureRecognizeralloc]initWithTarget:self action:@selector(reportXSwipe:)];

   //设置手势方向

   horizontal.direction= UISwipeGestureRecognizerDirectionLeft|UISwipeGestureRecognizerDirectionRight;

   [self.view addGestureRecognizer:horizontal];

   

   

}

 

 

#pragmamark -  手势发生后调用的方法

-(void)reportXSwipe:(UIGestureRecognizer *)recognizer

{

   self.lbltext.text = @"横向扫过";

   [selfperformSelector:@selector(eraseText) withObject:nil afterDelay:2.0f];

}

 

-(void)reportYSwipe:(UIGestureRecognizer *)recognizer

{

   self.lbltext.text = @"竖向扫过";

   [selfperformSelector:@selector(eraseText) withObject:nil afterDelay:2.0f];

}

 

 

//抹除文本标签中的文字

-(void)eraseText

{

   self.lbltext.text = @" ";

}

 

 

 

 

检查多根手指触摸

- (void)viewDidLoad

{

    [super viewDidLoad];

     //循环5次,生成5SwipGesturerecognizer,处理5根手指

   for(NSUIntegertouchCount = 1;touchCount <= 5;touchCount++) {

       UISwipeGestureRecognizer*vertical;

       vertical = [[UISwipeGestureRecognizeralloc]

                    initWithTarget:self action:@selector(reportVerticalSwipe:)];

       

      vertical.direction= UISwipeGestureRecognizerDirectionUp

       | UISwipeGestureRecognizerDirectionDown;

       vertical.numberOfTouchesRequired= touchCount;

      

      [self.view addGestureRecognizer:vertical];

       

       UISwipeGestureRecognizer*horizontal;

       horizontal = [[UISwipeGestureRecognizeralloc]

                       initWithTarget:self action:@selector(reportHorizontalSwipe:)];

       horizontal.direction= UISwipeGestureRecognizerDirectionLeft

       | UISwipeGestureRecognizerDirectionRight;

       horizontal.numberOfTouchesRequired= touchCount;

       [self.view addGestureRecognizer:horizontal];

   }

}

 

- (void)eraseText

{

   self.label.text = @"";

}

 

- (NSString *)descriptionForTouchCount:(NSUInteger)touchCount

{

   switch(touchCount) {

       case1:

            return@"一根手指";

       case2:

            return @"两根手指";

       case3:

            return @"三根手指";

       case4:

            return @"四根手指";

       case5:

            return @"五根手指";

       default:

            return @"";

   }

}

 

- (void)reportHorizontalSwipe:(UIGestureRecognizer *)recognizer

{

   self.label.text = [NSString stringWithFormat:@"%@ 根手指水平方向扫过",

                       [self descriptionForTouchCount:[recognizer numberOfTouches]]];

   [selfperformSelector:@selector(eraseText) withObject:nil afterDelay:2];

}

 

- (void)reportVerticalSwipe:(UIGestureRecognizer *)recognizer

{

   self.label.text = [NSString stringWithFormat:@"%@ 根手指垂直方向扫过",

                       [self descriptionForTouchCount:[recognizer numberOfTouches]]];

   [selfperformSelector:@selector(eraseText) withObject:nil afterDelay:2];

}

 

 

 

 

 

 

-----------------------------

 

使用点击识别器(UITapGestureRecognizer)

 

- (void)viewDidLoad

{

    [super viewDidLoad];

    //创建 点击识别器 对象

    UITapGestureRecognizer *singleTap =

    [[UITapGestureRecognizer alloc] initWithTarget:self

                                            action:@selector(singleTap)];

    singleTap.numberOfTapsRequired = 1;     //设置点击次数为 1 次

    singleTap.numberOfTouchesRequired = 1;  //设置 1 根手指

    [self.view addGestureRecognizer:singleTap];

   

    UITapGestureRecognizer *doubleTap =

    [[UITapGestureRecognizer alloc] initWithTarget:self

                                            action:@selector(doubleTap)];

    doubleTap.numberOfTapsRequired = 2;

    doubleTap.numberOfTouchesRequired = 1;

    [self.view addGestureRecognizer:doubleTap];

    //告诉单击感知器,如果双击操作未识别时触发自己的操作

   [singleTap requireGestureRecognizerToFail:doubleTap];

   

   UITapGestureRecognizer*tripleTap =

   [[UITapGestureRecognizeralloc]initWithTarget:self

                                            action:@selector(tripleTap)];

   tripleTap.numberOfTapsRequired= 3;

   tripleTap.numberOfTouchesRequired= 1;

   [self.view addGestureRecognizer:tripleTap];

   [doubleTap requireGestureRecognizerToFail:tripleTap];

   

   UITapGestureRecognizer*quadrupleTap =

   [[UITapGestureRecognizeralloc]initWithTarget:self

                                            action:@selector(quadrupleTap)];

   quadrupleTap.numberOfTapsRequired= 4;

   quadrupleTap.numberOfTouchesRequired= 1;

   [self.view addGestureRecognizer:quadrupleTap];

   [tripleTap requireGestureRecognizerToFail:quadrupleTap];

   //点击手势失败链。先检查 4 次点击是否有识别器,如果没有,检查 3 次点击是否有识别器….

}

 

 

- (void)singleTap

{

   self.singleLabel.text = @"Single Tap Detected";

   [selfperformSelector:@selector(clearLabel:)

               withObject:self.singleLabel

               afterDelay:1.6f];

}

 

- (void)doubleTap

{

   self.doubleLabel.text = @"Double Tap Detected";

   [selfperformSelector:@selector(clearLabel:)

               withObject:self.doubleLabel

               afterDelay:1.6f];

}

 

- (void)tripleTap

{

   self.tripleLabel.text = @"Triple Tap Detected";

   [selfperformSelector:@selector(clearLabel:)

               withObject:self.tripleLabel

               afterDelay:1.6f];

}

 

- (void)quadrupleTap

{

   self.quadrupleLabel.text = @"Quadruple Tap Detected";

   [selfperformSelector:@selector(clearLabel:)

               withObject:self.quadrupleLabel

               afterDelay:1.6f];

}

 

- (void)clearLabel:(UILabel *)label

{

   label.text= @"";

}

 

 

使用缩放识别器(UIPinchGestureRecognizer)

@property(non

 

-(void)viewDidLoad

{

  UIPinchGestureRecognizer *pich = [[UIPinchGestureRecognizer alloc]initWithTarget:self

              action:@selector(doPinch:)];

   [self.view addGestureRecognizer:pich];

}

 

 

-(void)doPinch: (UIPinchGestureRecognizer  *)pinch

{

  if(pinch.state == UIPinchGestureRecognizerStateBegan)

  {

        initFontSize = label1.font.pointsize;

  }

  else

  {

        label1.font = [label1.fontfontWithSize:initFontSize*pinch.scale];

  }

}

 

 

 

 

同时实现“缩放”“旋转”手势识别器

1、头文件实现协议

<UIGestureRecognizerDelegate>

2、

 

//scale缩小

//rotation 旋转

@implementationBIDViewController {

   CGFloatscale, previousScale;

   CGFloatrotation, previousRotation;

}

 

- (void)viewDidLoad

{

   [superviewDidLoad];

 

   previousScale= 1;

   

   UIImage*image = [UIImageimageNamed:@"yosemite-meadows.png"];

   self.imageView = [[UIImageView alloc] initWithImage:image];

   //能否配合使用

   self.imageView.userInteractionEnabled = YES;

   self.imageView.center = CGPointMake(160, 160);

   [self.view addSubview:self.imageView];

   

   UIPinchGestureRecognizer*pinchGesture =

   [[UIPinchGestureRecognizeralloc]initWithTarget:self action:@selector(doPinch:)];

   pinchGesture.delegate= self;

   [self.imageView addGestureRecognizer:pinchGesture];

 

   UIRotationGestureRecognizer*rotationGesture =

   [[UIRotationGestureRecognizeralloc]initWithTarget:self action:@selector(doRotate:)];

   rotationGesture.delegate= self;

   [self.imageView addGestureRecognizer:rotationGesture];

}

 

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizershouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer

{

   returnYES;

}

 

- (void)transformImageView

{

   CGAffineTransformt = CGAffineTransformMakeScale(scale * previousScale,

                                                    scale* previousScale);

   t = CGAffineTransformRotate(t,rotation+ previousRotation);

   self.imageView.transform = t;

}

 

- (void)doPinch:(UIPinchGestureRecognizer *)gesture

{

   scale= gesture.scale;

   [selftransformImageView];

   if(gesture.state== UIGestureRecognizerStateEnded){

       previousScale= scale* previousScale;

       scale= 1;

   }

}

 

- (void)doRotate:(UIRotationGestureRecognizer *)gesture

{

   rotation= gesture.rotation;

   [selftransformImageView];

   if(gesture.state== UIGestureRecognizerStateEnded){

       previousRotation= rotation+ previousRotation;

       rotation= 0;

   }

}

 

 

 

总结:

1、补充图形处理的方法:上下文栈、界面重绘(作业,动画机器猫)

2、触摸、手势概念

3、使用手势对象(作业:完成图片的缩放、旋转)

4、了解手势执行的过程(思考:如何判断移动方向)

 

检查 猜图游戏 项目

 

 

 

 

 

 

 

 

补充:

1、NSObject 类中让方法延迟执行

 

 

2、擦碰(滑动)识别器

 

3、点击识别器

 

 

4、上下文状态栈,避免效果冲突

- (void)drawRect:(CGRect)rect

{

    // draw a rounded rect bezier path filled with blue

    CGContextRef aRef = UIGraphicsGetCurrentContext();

 

    //把当前的上下文状态保存到   状态栈中

    CGContextSaveGState(aRef);

 

    //你自己的绘图代码

    UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:5.0f];

    [bezierPath setLineWidth:5.0f];

    [[UIColor blackColor] setStroke];

   

    UIColor *fillColor = [UIColor colorWithRed:0.529 green:0.808 blue:0.922 alpha:1]; // color equivalent is #87ceeb

    [fillColor setFill];

   

    [bezierPath stroke];

    [bezierPath fill];

 

     //绘制完毕,从状态栈中还原   

    CGContextRestoreGState(aRef);

}

 

 

 

 

5、了解界面重绘

//通知 MyView 让它重绘整个页面

   //该方法自动调用 - (void)drawRect:(CGRect)rect

   //整个界面重绘

   [self.myView setNeedsDisplay];

   //在指定范围内,重绘,节约内存

   //[self.myViewsetNeedsDisplayInRect:(CGRect)]

 

你可能感兴趣的:(类,移动开发,多点触摸,对象,触摸)