IOS开发教程第一季之02UI进阶day7合并IOS学习018--响应者对象、单多点触摸,手势解锁案例

1.响应者对象
  • 在IOS中,只有继承了UIResponder的对象才能接收并处理事件,我们称之为“响应者对象”
  • UIApplication,UIViewController,UIView都继承自UIResponder,因此他们都是响应者对象,都能够接收并处理事件
    UIResponder内部提供了一下方法来处理事件
    在这里插入图片描述
#import "FRView.h"

@implementation FRView
//手指接触到这个view时调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  NSLog(@"%s",__func__);
}
//手指在这个view移动的时候调用
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  NSLog(@"%s",__func__);
}
//手指在view上松开的时候调用
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  NSLog(@"%s",__func__);
}
//意外终止(如被电话打断)
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  NSLog(@"%s",__func__); 
}

@end
2.手势的几个属性
//手指接触到这个view时调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  UITouch* touch=touches.anyObject;
  //NSLog(@"%ld",touch.tapCount);//快速点击的次数
  //NSLog(@"%ld",touch.phase);//触摸的阶段
  NSLog(@"%@",touch.window);//获取触摸事件产生的窗口
  NSLog(@"%@",[UIApplication sharedApplication].keyWindow);//获取主窗口
  NSLog(@"%@",self.window);//获取当前view所在的窗口
  NSLog(@"%@",touch.view);//获取当前view
  NSLog(@"%@",self);//获取自己
  CGPoint p=[touch locationInView:self];//在自己这个self中触摸的位置
  CGPoint p1=[touch locationInView:self.superview];//在父控件这个self中触摸的位置
  NSLog(@"%@",NSStringFromCGPoint(p1));
}
//手指在这个view移动的时候调用
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  UITouch* touch=touches.anyObject;
  CGPoint p=[touch locationInView:self];
  NSLog(@"%@当前点",NSStringFromCGPoint(p));//当前点
  CGPoint lastP=[touch previousLocationInView:self];
  NSLog(@"%@上一个点",NSStringFromCGPoint(lastP));//上一个点
}
3.单点触摸
#import "FRView.h"

@implementation FRView
//手指接触到这个view时调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
 //获取触摸对象
  UITouch* touch=touches.anyObject;
  
  CGPoint point=[touch locationInView:self.superview];//获取绿色的view父控件的点的位置
  
  //让绿色的view的中心等于手指的位置
  self.center=point;
  
}

//手指在这个view移动的时候调用
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
 //获取触摸对象
 UITouch* touch=touches.anyObject;
  
  //获取当前的位置
  CGPoint point=[touch locationInView:self.superview];//获取view的父控件的点
  
  //获取上一个点的位置
  CGPoint lastPoint=[touch previousLocationInView:self.superview];
  
  //计算偏移量
  CGFloat offsetX=point.x-lastPoint.x;
  CGFloat offsetY=point.y-lastPoint.y;
  
  //让绿色的view的center在自己的位置基础上+偏移量
  self.center=CGPointMake(self.center.x+offsetX, self.center.y+offsetY);

  //让绿色的view的中心等于手指位置
  //self.center=point;
}
//手指在view上松开的时候调用
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

}
//意外终止(如被电话打断)
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

  
}

@end

效果:view被拖动

4.多点触摸

将当前view的类指定为FRView

#import "FRView.h"
@interface FRView()
@property(nonatomic,strong)NSArray *images;

@end
@implementation FRView

#pragma mark  --------懒加载数据-------
//重写images的get方法
-(NSArray*)images{
  if (!_images) {
    _images=@[[UIImage imageNamed:@"spark_blue"],[UIImage imageNamed:@"spark_green"]];
  }
  
  return _images;
}
//手指接触到这个view时调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
 //touchs作为集合有几个元素索命有几个触摸点
  NSLog(@"%ld",touches.count);
  [self addimageView:touches];
}

//手指在这个view移动的时候调用
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  [self addimageView:touches];

  
}

-(void)addimageView:(NSSet<UITouch *> *)touches {
  int i=0;
  for (UITouch* touch in touches) {
    
     //获取手指的位置
     CGPoint point=[touch locationInView:touch.view];//触摸的view
     
     //创建一个imageview
    UIImageView* imageView= [[UIImageView alloc]initWithImage:self.images[i]];
     
     //设置imageview的中心为手指的位置
     imageView.center=point;
     
     //把imageview加到当前的大view上
     [self addSubview:imageView];
     
     //动画移除当前点,2秒内imageview的透明度为零然后移除
     
     
     [UIView animateWithDuration:2 animations:^{
       imageView.alpha=0;

     } completion:^(BOOL finished) {
       [imageView removeFromSuperview];
     }];
    i++;
  }
  
  
}
//手指在view上松开的时候调用
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

}
//意外终止(如被电话打断)
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

  
}

@end

在这里插入图片描述

5.时间的产生和传递

在这里插入图片描述

6.手势解锁案例

这是个冗长的案例,中规中矩
在storyboard中创建一个view,对应FRView

FRView.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface FRView : UIView
//创建一个自定义block
@property(nonatomic,copy)BOOL (^passwordBlock)(NSString*);
@end

NS_ASSUME_NONNULL_END

FRView.m

#import "FRView.h"
#define kButtonCount 9
@interface FRView()
@property(nonatomic,strong)NSMutableArray* buttons;//9个按钮
@property(nonatomic,strong)NSMutableArray* lineButtons;//需要连线的按钮个按钮
@property(nonatomic,assign)CGPoint currentPoint;//当前的手指位置

@end

@implementation FRView
#define mark ------懒加载数据--------
//重写buttons属性的get方法
-(NSMutableArray*)buttons{
  if (!_buttons) {
    _buttons=[NSMutableArray array];
    //添加9个按钮
    for (int i=0; i<kButtonCount; i++) {
      //创建一个button
      UIButton* button=[[UIButton alloc]init];
      //给button设置一个tag
      button.tag=i;
      //给button设置一个正常状态下的背景图
      [button setBackgroundImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
      //设置button高亮(选中状态)
      [button setBackgroundImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
      
      //设置button错误的图片(可用状态)
      [button setBackgroundImage:[UIImage imageNamed:@"gesture_node_error"] forState:UIControlStateDisabled];
      
      //禁用button的用户交互
      button.userInteractionEnabled=NO;
      [self addSubview:button];
      //把循环创建的button添加到数组中去
      [_buttons addObject:button];
      //[self.buttons addObject:button];
    }
  }
  return _buttons;
}

//初始化lineButtons
-(NSMutableArray*)lineButtons{
  if (!_lineButtons) {
    _lineButtons=[NSMutableArray array];
  }
  return _lineButtons;
}

//当手指触摸到应用是
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
 //获取触摸的点
  UITouch* touch=touches.anyObject;
  //获取手指的位置,touch所在view的位置
  CGPoint point=[touch locationInView:touch.view];
  
  for (int i=0; i<self.buttons.count; ++i) {
    //获取button
    UIButton* button=self.buttons[i];
    //如果button的frame包含这个点
    if (CGRectContainsPoint(button.frame, point)) {
      //让按钮亮起来
      button.selected=YES;
      //高亮的按钮添加到需要划线的数组中
      [self.lineButtons addObject:button];
    }
  }
}

//设置手指离开时候的手势
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  //修改最后手指的位置为需要连线的最后一个按钮的中心,解决最后一根线多出来的问题
  self.currentPoint=[[self.lineButtons lastObject]center];
  //重绘
  [self setNeedsDisplay];
  //让所有需要划线的button都变成错误的样式
  for (int i=0; i<self.lineButtons.count; ++i) {
    //获取button
    UIButton* button=self.lineButtons[i];
    //让button变成错误状态的时候需要取消选中状态
    button.selected=NO;
    
    //让button变成不可用状态
    button.enabled=NO;
 
  }
  

  //拼接密码
  NSString* password=@"";
  for (int i=0; i<self.lineButtons.count; ++i) {
    //获得按钮
    UIButton* button=self.lineButtons[i];
    //拼接密码
    password=[password stringByAppendingString:[NSString stringWithFormat:@"%ld",  button.tag]];
  
   }
  
  //判断password里面是否有值
  if (self.passwordBlock) {
    if (self.passwordBlock(password)) {
      NSLog(@"密码正确");
    }else{
      NSLog(@"密码错误");
    }
  }
  
  NSLog(@"%@",password);
  
  //关闭用户交互
     [self setUserInteractionEnabled:NO];
     //间隔一段时间再清空所有按钮
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(3*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
       //开启用户交互
       [self setUserInteractionEnabled:YES];
       //清空所有按钮
       [self clear];
     });
}

//清空所有按钮的方法
-(void)clear{
  for (int i=0; i<self.buttons.count; i++) {
    UIButton* button=self.buttons[i];
    //取消按钮的高亮状态(选中状态)
    button.selected=NO;
    //让按钮取消错误的样式
    button.enabled=YES;
  }
  
  //清空所有线条
  [self.lineButtons removeAllObjects];
  //重绘一下
  [self setNeedsDisplay];
}

//设置手指在移动时候的的手势
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  //获取触摸对象
  UITouch* touch=touches.anyObject;
  //获取手指的最新位置
  CGPoint point=[touch locationInView:touch.view];
  //给全局属性的手指位置赋值
  self.currentPoint=point;
  
  for (int i=0; i<self.buttons.count; ++i) {
     UIButton* button=self.buttons[i];
    //判断手指是否在某个按钮的范围之内
    if (CGRectContainsPoint(button.frame, point)) {
          button.selected=YES;
      
      //判断,如果已经加到了数组当中,那么不在去添加
      if (![self.lineButtons containsObject:button]) {
        //高亮的按钮添加到需要划线的数组中
        [self.lineButtons addObject:button];
      }
      
    }
  }
  //重绘自己
  [self setNeedsDisplay];
}
//按钮间的连线
- (void)drawRect:(CGRect)rect{
  //如果没有起点则不要绘制,直接返回
  if (!self.lineButtons.count) {
    return;
  }
  
  //创建路径
  UIBezierPath* path=[UIBezierPath bezierPath];
  
  for (int i=0; i<self.lineButtons.count; ++i) {
    //获取button
    UIButton* button=self.lineButtons[i];
    //如果是起始点则让画起点到这个位置的中心,如果不是起点则话重点到这个位置的中心
    if (i==0) {
      
      [path moveToPoint:button.center];
    }else{
      [path addLineToPoint:button.center];
    }
  }
  //连线到手指的位置
  [path addLineToPoint:self.currentPoint];
  
  //设置颜色
  [[UIColor whiteColor]set];
  //设置线宽
  [path setLineWidth:10];
  //设置连接处的样式
  [path setLineJoinStyle:kCGLineJoinRound];
  [path setLineCapStyle:kCGLineCapRound];
  //渲染线条
  [path stroke];
}

//,排列子视图,计算9宫格
- (void)layoutSubviews{
  [super layoutSubviews];
  CGFloat w=74;
  CGFloat h=w;
  int colCount=3;
  CGFloat margin=(self.frame.size.width-3*w)/4;

  for (int i=0; i<kButtonCount; ++i) {
    //计算九宫格位置
    CGFloat x=(i%colCount)*(margin+w)+margin;
    CGFloat y=(i/colCount)*(margin+w)+margin;
      
    [self.buttons[i] setFrame:CGRectMake(x, y, w, h)];
  }
}

@end
  

ViewController.m

#import "ViewController.h"
#import "FRView.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet FRView *passowrdView;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  //设置ViewController背景图片,直接使用UIColor的colorWithPatterImage背景色方法
  self.view.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed: @"Home_refresh_bg"]];
  //密码
  //NSString* strpassword=@"012";
  self.passowrdView.passwordBlock=^(NSString* strpwd){
    if ([strpwd isEqualToString:@"012"]) {
      return YES;
    }else{
      return NO;
    }
  };
  
}

@end

效果,截图不能显示交互
在这里插入图片描述
代码在这里下载,这次没有过程……
案例代码下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值