UIControl的小秘密——额外的70像素

UIControl是App开发中每天都需要使用,每一个IOS开发者对于UIControl都是无比熟悉的,UIButton、UISlider、UISwitch等等。  
而我们使用这些控件的主要方式就是通过UIControl提供给我们的`Control Event`

```
enum {
   UIControlEventTouchDown           = 1 <<  0,
   UIControlEventTouchDownRepeat     = 1 <<  1,
   UIControlEventTouchDragInside     = 1 <<  2,
   UIControlEventTouchDragOutside    = 1 <<  3,
   UIControlEventTouchDragEnter      = 1 <<  4,
   UIControlEventTouchDragExit       = 1 <<  5,
   UIControlEventTouchUpInside       = 1 <<  6,
   UIControlEventTouchUpOutside      = 1 <<  7,
   UIControlEventTouchCancel         = 1 <<  8,
   
   UIControlEventValueChanged        = 1 << 12,
   
   UIControlEventEditingDidBegin     = 1 << 16,
   UIControlEventEditingChanged      = 1 << 17,
   UIControlEventEditingDidEnd       = 1 << 18,
   UIControlEventEditingDidEndOnExit = 1 << 19,
   
   UIControlEventAllTouchEvents      = 0x00000FFF,
   UIControlEventAllEditingEvents    = 0x000F0000,
   UIControlEventApplicationReserved = 0x0F000000,
   UIControlEventSystemReserved      = 0xF0000000,
   UIControlEventAllEvents           = 0xFFFFFFFF
};
```

这些control event对于我们来说也不太陌生,正是由这些简单的event拼凑成了我们应用的交互。

不过这里面却是有一个小秘密。


##小秘密——70像素
小秘密是什么呢?  

如果你用过`UIControlEventTouchDragExit`  
并且你对于`UIControlEventTouchDragExit`的触摸时机较为敏感的话,你就会发现如果手指离开我们的Control的bounds的那一刻,`UIControlEventTouchDragExit`并没有被触发?  
可是苹果的文档写写相当清楚,当手指离开了bounds的时候就应该触发。
```
UIControlEventTouchDragExit
    
    An event where a finger is dragged from within a control to outside its bounds.
    Available in iOS 2.0 and later.
    Declared in UIControl.h.
```

事实是检验真理的唯一标准?
所以我试着输出了一下`UIControlEventTouchDragExit`被触发时候touch的坐标。

结果就是`70像素左右`,每次触发时候的位置都是距离control的边界70像素左右

可能文字描述的不够形象。放张图


图中的红色边框就是一个按钮的bounds  
而图中的绿色边框就是事件触发时候的区域边界  
当手指越过绿色边框的时候,事件就被触发了  
而红色边框和绿色边框之间的距离是`70像素`

那是不是其他的contrl event是不是符合这个规律呢?  
我做了简单的测试,发现是的
`UIControlEventTouchDragInside`、`UIControlEventTouchDragOutside`等等的触发边界都是70像素左右。

##自定义触发边界
不得不说,有时候这多出来的70像素是相当的讨厌的,因为我们不需要,那么我们是否能够去自定义呢?  

答案当然是肯定的。

还是以`UIControlEventTouchDragExit`为例吧,让我们来修改`UIControlEventTouchDragExit`的触发边界

贴出一段代码
```
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    // 设置新的边界
    CGFloat boundsExtension = 25.0f;
    CGRect outerBounds = CGRectInset(self.bounds, -1 * boundsExtension, -1 * boundsExtension);
    
    // 判断触摸位置
    BOOL touchOutside = !CGRectContainsPoint(outerBounds, [touch locationInView:self]);
    if(touchOutside)
    {
        // 判断是UIControlEventTouchDragExit/UIControlEventTouchDragOutside
        BOOL previousTouchInside = CGRectContainsPoint(outerBounds, [touch previousLocationInView:self]);
        if(previousTouchInside)
        {
            [self sendActionsForControlEvents:UIControlEventTouchDragExit];
        }
        else
        {
            [self sendActionsForControlEvents:UIControlEventTouchDragOutside];
        }
    }
    // 如果不是想要修改的control event,返回原操作
    return [super continueTrackingWithTouch:touch withEvent:event];
}
```

##感想
虽然自己也每天使用UIControl,不过也是现在才发现这个有趣的现象,IOS中还是有很多东西需要探索,每日自省自勉。

posted @ 2014-03-29 12:06  Peter潘  阅读(1776)  评论(0编辑  收藏  举报