1.系统是如何判断控件状态的
在UIControl中有这个方法
- (void)sendActionsForControlEvents:(UIControlEvents)controlEvents;
用它来发送控件状态。
什么时候发送对应状态,我们可以自己来进行来判断。
这要用到以下几个UIResponder中的方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- 在touchesBegan时,要发送UIControlEventTouchDown事件。
- 在touchesMoved中,根据前一刻point和当前时刻的point,来判断发送UIControlEventTouchDragInside,UIControlEventTouchDragOutside,UIControlEventTouchDragEnter或UIControlEventTouchDragExit事件。
- 在touchesEnded的时,应该发送UIControlEventTouchUpInside或UIControlEventTouchUpOutside事件。
- 在touchesCancelled时,要发送UIControlEventTouchCancel。
控件highlighted只要直接赋值YES 或 NO 就可以了。
- 在touchesBegan时 highlighted为YES
- 在touchesEnded和touchesCancelled时 highlighted应该为NO。
- 在touchesMoved中,要判断触碰的位置来设置highlighted的值。
2.如何判断触碰的位置
在UITouch中有以下两个方法。
- (CGPoint)locationInView:(nullable UIView*)view;//获得当前触摸点的point
- (CGPoint)previousLocationInView:(nullable UIView *)view;//获得先前触摸点的point
结合CoreGraphics中的 bool CGRectContainsPoint(CGRect rect, CGPoint point)
方法来判断触碰点与控件的关系
以touchesEnded和touchesMoved为例。
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.highlighted = NO;
CGPoint point = [touches.anyObject locationInView:self];
if (CGRectContainsPoint(self.bounds, point)) { //判断point是否在self.bounds内。
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
} else {
[self sendActionsForControlEvents:UIControlEventTouchUpOutside];
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = touches.anyObject;
BOOL currentInside = CGRectContainsPoint(self.bounds, [touch locationInView:self]);
BOOL preInside = CGRectContainsPoint(self.bounds, [touch previousLocationInView:self]);
if (currentInside) {
self.highlighted = YES;
if (preInside) {
[self sendActionsForControlEvents:UIControlEventTouchDragInside];
} else {
[self sendActionsForControlEvents:UIControlEventTouchDragEnter];
}
} else {
self.highlighted = NO;
if (preInside) {
[self sendActionsForControlEvents:UIControlEventTouchDragExit];
} else {
[self sendActionsForControlEvents:UIControlEventTouchDragOutside];
}
}
}
以上这些,其实可以让系统来做,只要调用即可。
[super touchesXXX:touches withEvent:event]
例如:
以下代码就等于上面的一大段的touchesMoved方法了。
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
}
3.系统的方法如此简便,那为什么我们还要重写touches系列的方法
因为系统的touchesMoved在手指移动时,大概是离开控件70pt左右内,控件仍然会处于高亮的状态,这时touchesEnded则会触发UIControlEventTouchUpInside事件。
现实中,我们会遇到许多奇奇怪怪的需求,系统原本的方法不足以满足需求,这就需要我们自己来重写方法了。
去研究,探索系统的方法是如何实现的,最终学会创新,这是件非常有趣的事。