事件传递和响应者链条

2018-09-03  本文已影响7人  yanhooIT

事件处理

// 触摸事件(重点)
// 一根或者多根手指**开始**触摸view,系统会自动调用view的下面方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
// 一根或者多根手指在view上**移动**,系统会自动调用view的下面方法(随着手指的移动,会持续调用该方法)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
// 一根或者多根手指**离开**view,系统会自动调用view的下面方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
// 触摸结束前,某个系统事件(例如:电话呼入)会打断触摸过程,系统会自动调用view的下面方法
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

// 加速计事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;

// 远程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
// *************************常用属性***************************
// 事件类型
@property(nonatomic,readonly) UIEventType     type;
// 子事件类型
@property(nonatomic,readonly) UIEventSubtype  subtype;
/*
typedef NS_ENUM(NSInteger, UIEventType) {
    UIEventTypeTouches,// 触摸事件
    UIEventTypeMotion, // 加速计事件
    UIEventTypeRemoteControl,// 远程控制事件
};

typedef NS_ENUM(NSInteger, UIEventSubtype) {
    // available in iPhone OS 3.0
    UIEventSubtypeNone                              = 0,

    // 加速计事件的子事件类型
    // for UIEventTypeMotion, available in iPhone OS 3.0
    UIEventSubtypeMotionShake                       = 1,

    // 远程控制事件的子事件类型
    // for UIEventTypeRemoteControl, available in iOS 4.0
    UIEventSubtypeRemoteControlPlay                 = 100,
    UIEventSubtypeRemoteControlPause                = 101,
    UIEventSubtypeRemoteControlStop                 = 102,
    UIEventSubtypeRemoteControlTogglePlayPause      = 103,
    UIEventSubtypeRemoteControlNextTrack            = 104,
    UIEventSubtypeRemoteControlPreviousTrack        = 105,
    UIEventSubtypeRemoteControlBeginSeekingBackward = 106,
    UIEventSubtypeRemoteControlEndSeekingBackward   = 107,
    UIEventSubtypeRemoteControlBeginSeekingForward  = 108,
    UIEventSubtypeRemoteControlEndSeekingForward    = 109,
};
*/

// 事件产生的时间
@property(nonatomic,readonly) NSTimeInterval  timestamp;

// UIEvent还提供了相应的方法可以获得在某个view上面的触摸对象(UITouch)
- (NSSet *)allTouches;
- (NSSet *)touchesForWindow:(UIWindow *)window;
- (NSSet *)touchesForView:(UIView *)view;
- (NSSet *)touchesForGestureRecognizer:(UIGestureRecognizer *)gesture

触摸事件处理

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    NSLog(@"%@---%s",NSStringFromClass([self class]),__func__);

    // 系统默认做法
//    return [super hitTest:point withEvent:event];

    // 模仿系统做法找到最合适的控件的做法
    return [self findTheRightView:point withEvent:event];
}

/**
 *  模仿系统做法找到最合适的控件的做法
 */
- (UIView *)findTheRightView:(CGPoint)point withEvent:(UIEvent *)event
{
    // 1.判断当前控件能否接收事件
    if (!self.userInteractionEnabled
        || self.hidden
        || self.alpha <= 0.01) return nil;

    // 2. 判断点在不在当前控件
    if (![self pointInside:point withEvent:event]) return nil;

    // 3.从后往前遍历自己的子控件
    NSInteger count = self.subviews.count;
    for (NSInteger i = count - 1; i >= 0; i--)
    {
        UIView *childView = self.subviews[i];

        // 把当前控件上的坐标系转换成子控件上的坐标系
        CGPoint childP = [self convertPoint:point toView:childView];
        // 递归找到最合适处理事件的控件
        UIView *rightView = [childView findTheRightView:childP withEvent:event];

        if (rightView) return rightView;
    }

    // 循环结束,表示没有比自己更合适的处理事件的view
    return self;
}
/**
 *  控制返回最合适处理事件的控件
 */
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    // 将当前坐标点转化为相对按钮左上角(0,0)坐标点
    CGPoint btnPoint = [self convertPoint:point toView:self.btn];

    // CGRectContainsPoint用于判断一个点是否在指定区域,左上角参考点(0,0)必须一致才有可比性
    // 由于btnPoint已经被转化为相对按钮的左上角的坐标点了,所以不能用此函数判断点是否在指定区域内
//    BOOL isContain = CGRectContainsPoint(self.btn.frame, btnPoint);
//    NSLog(@"self.btn.frame-->%@",NSStringFromCGRect(self.btn.frame));
//    NSLog(@"btnPoint-->%@",NSStringFromCGPoint(btnPoint));

    // 只要点在按钮上就交由按钮处理对应的事件
    if([self pointInside:btnPoint withEvent:event])
    {
        return self.btn;
    }

    return [super hitTest:point withEvent:event];
}

手势识别

// 创建手势识别器对象
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
// 连续敲击2次
tap.numberOfTapsRequired = 2;
// 需要2根手指一起敲击
tap.numberOfTouchesRequired = 2;
// 添加手势识别器到对应的view上,那么就可以在此view应用对应的手势
[self.iconView addGestureRecognizer:tap];
// 监听手势
[tap addTarget:self action:@selector(tapIconView:)];
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
    // 没有触摸事件发生,所有手势识别的默认状态
    UIGestureRecognizerStatePossible,
    // 一个手势已经开始但尚未改变或者完成时
    UIGestureRecognizerStateBegan,
    // 手势状态改变
    UIGestureRecognizerStateChanged,
    // 手势完成
    UIGestureRecognizerStateEnded,
    // 手势取消,恢复至Possible状态
    UIGestureRecognizerStateCancelled,
    // 手势失败,恢复至Possible状态
    UIGestureRecognizerStateFailed,

    UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
};
// 每个手势设置代理
// 是否允许同时支持多个手势,默认是不支持多个手势
// 返回yes表示支持多个手势
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}
#pragma mark - 旋转手势
- (void)setUpRotation
{
    UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];
    rotation.delegate = self;
    [self.imageView addGestureRecognizer:rotation];
}

// 默认传递的旋转的角度都是相对于最开始的位置
- (void)rotation:(UIRotationGestureRecognizer *)rotation
{
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotation.rotation);

    // 复位,这个很重要!!!
    rotation.rotation = 0;
}

#pragma mark - 捏合
- (void)setUpPinch
{
    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];
    pinch.delegate = self;
    [self.imageView addGestureRecognizer:pinch];
}

- (void)pinch:(UIPinchGestureRecognizer *)pinch
{
    self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinch.scale, pinch.scale);

    // 复位,这个很重要!!!
    pinch.scale = 1;
}

#pragma mark - 拖拽
- (void)setUpPan
{
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];

    pan.delegate = self;

    [self.imageView addGestureRecognizer:pan];
}

- (void)pan:(UIPanGestureRecognizer *)pan
{
    // 移动视图
    // 获取手势的移动,也是相对于最开始的位置
    CGPoint transP = [pan translationInView:self.imageView];

    self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, transP.x, transP.y);

    // 复位,这个很重要!!!
    [pan setTranslation:CGPointZero inView:self.imageView];
}
上一篇下一篇

猜你喜欢

热点阅读