iOS中View的拖拽

1、UITouch

UITouch的属性

image


//触摸产生时所处的窗口
@property (nonatomic , readonly, retain) UIWindow *window;
//触摸产生时所处的视图
@property (nonatomic , readonly, retain)UIView *view;
//短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击
@property (nonatomic , readonly) NSUInteger tapCount ;
//记录了触摸事件产生或变化时的时间,单位是秒
@property (nonatomic, readonly) NSTimeInterval timestamp ;
//当前触摸事件所处的状态
@property (nonatomic, readonly) UITouchPhase phase;

UITouch的方法

//返回值表示触摸在view上的位置
//这里返回的位置是针对view的坐标系的(以view的左上角为原点[0, 0])
//调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
- (CGPoint) locationInView: (UIView *)view;

//该方法记录了前一个触摸点的位置
- (CGPoint) previousLocationInView: (UIView *)view;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
     // 获取当前点
    CGPoint currentPoint = [touch locationInView:self];
      //获取上一个点
    CGPoint previousPoint = [touch previousLocationInView:self];
    //获取XY轴偏移量
    CGFloat offsetX = currentPoint.x - previousPoint.x;
    CGFloat offsetY = currentPoint.y - previousPoint.y;
    //修改View的位置(frame,center,transform)
    //从当期位置计算偏移量
    self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);
    //每次都是从0计算偏移量
//    self.transform = CGAffineTransformMakeTranslation(offsetX, offsetY);
}
注意:即使用多跟手指同时拖动一个View,也只为产生一个UITouch对象,通过更改self.multipleTouchEnabled属性可以实现产生多个UITouch对象,但是不建议这么做。

响应者对象UIResponder

  • 在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件。我们称之为“响应者对象”
  • UIApplication、UIViewController、UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件
UIResponder内部提供了以下方法来处理事件
触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (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;

UIEvent

image

每产生一个事件,就会产生一个UIEvent对象

UIEvent:称为事件对象,记录事件产生的时刻和类型

常见属性
事件类型
@property(nonatomic,readonly) UIEventType     type;
@property(nonatomic,readonly) UIEventSubtype  subtype;

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

UIEvent还提供了相应的方法可以获得在某个view上面的触摸对象(UITouch)
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,
};

image
image
image
image
image
image
image

HitTest

HitTest练习如下:
// hitTest:withEvent:作用:就是用来寻找最合适的view
//什么时候调用:当一个事件传递给当前View的时候调用
//返回值:返回是谁,谁就是最适合的view,就会调用该view的touch方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{

    // 当前控件上的点转换到chatView上
    CGPoint chatP = [self convertPoint:point toView:self.chatView];
    // 判断下点在不在chatView上
    if ([self.chatView pointInside:chatP withEvent:event]) {
        return self.chatView;
    }else{
        return [super hitTest:point withEvent:event];
    }
}                                                                       
//作用:寻找最适全的View
//参数:point 当前手指的点.  event当前的事件.
//什么时候调用:当一个事件传递给当前View的时候就会调用.
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
//    return [super hitTest:point withEvent:event];
    //1.判断自己能否接收事件
    if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01){
        return nil;
    }
    //2.触摸点在不在当前的View.
    if (![self pointInside:point withEvent:event]) {
        return nil;
    }
    //3.从后往前遍历出自己的子控件.重复前两步操作,看自己子控件是不是最适合的Viwe.
    int count = (int)self.subviews.count;
    for (int i = count -1; i >= 0; i--) {
    UIView *childV = self.subviews[i];
    //把当前的点转换成childV坐标系的点.
    CGPoint childPoint = [self convertPoint:point toView:childV];
    //判断子控件是不是最适合的View.
    UIView *fitView = [childV hitTest:childPoint withEvent:event];
        if (fitView) {
            return fitView;
        }
    }
    //4.如果没有符合条件的子控件,那么它自己就是这个最适合的View.
    return  self;
}

//hitTest底层会调用pointInside.
//判断当前点在不在当前的view上.
//point点必须是跟当前View同一坐标系的点.
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    return YES;
}

   转载规则


《iOS中View的拖拽》 刘星星 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录