I have a custom UIButton with UILabel added as subview. Button perform given selector only when I touch it about 15points lower of top bound. And when I tap above that area
Extending Alexander's solution:
Step 1. Subclass UIWindow
@interface ChunyuWindow : UIWindow {
NSMutableArray * _views;
@private
UIView *_touchView;
}
- (void)addViewForTouchPriority:(UIView*)view;
- (void)removeViewForTouchPriority:(UIView*)view;
@end
// .m File
// #import "ChunyuWindow.h"
@implementation ChunyuWindow
- (void) dealloc {
TT_RELEASE_SAFELY(_views);
[super dealloc];
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (UIEventSubtypeMotionShake == motion
&& [TTNavigator navigator].supportsShakeToReload) {
// If you're going to use a custom navigator implementation, you need to ensure that you
// implement the reload method. If you're inheriting from TTNavigator, then you're fine.
TTDASSERT([[TTNavigator navigator] respondsToSelector:@selector(reload)]);
[(TTNavigator*)[TTNavigator navigator] reload];
}
}
- (void)addViewForTouchPriority:(UIView*)view {
if ( !_views ) {
_views = [[NSMutableArray alloc] init];
}
if (![_views containsObject: view]) {
[_views addObject:view];
}
}
- (void)removeViewForTouchPriority:(UIView*)view {
if ( !_views ) {
return;
}
if ([_views containsObject: view]) {
[_views removeObject:view];
}
}
- (void)sendEvent:(UIEvent *)event {
if ( !_views || _views.count == 0 ) {
[super sendEvent:event];
return;
}
UITouch *touch = [[event allTouches] anyObject];
switch (touch.phase) {
case UITouchPhaseBegan: {
for ( UIView *view in _views ) {
if ( CGRectContainsPoint(view.frame, [touch locationInView:[view superview]]) ) {
_touchView = view;
[_touchView touchesBegan:[event allTouches] withEvent:event];
return;
}
}
break;
}
case UITouchPhaseMoved: {
if ( _touchView ) {
[_touchView touchesMoved:[event allTouches] withEvent:event];
return;
}
break;
}
case UITouchPhaseCancelled: {
if ( _touchView ) {
[_touchView touchesCancelled:[event allTouches] withEvent:event];
_touchView = nil;
return;
}
break;
}
case UITouchPhaseEnded: {
if ( _touchView ) {
[_touchView touchesEnded:[event allTouches] withEvent:event];
_touchView = nil;
return;
}
break;
}
default: {
break;
}
}
[super sendEvent:event];
}
@end
Step 2: Assign ChunyuWindow instance to AppDelegate Instance
Step 3: Implement touchesEnded:widthEvent: for view with buttons, for example:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded: touches withEvent: event];
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView: _buttonsView]; // a subview contains buttons
for (UIButton* button in _buttons) {
if (CGRectContainsPoint(button.frame, point)) {
[self onTabButtonClicked: button];
break;
}
}
}
Step 4: call ChunyuWindow's addViewForTouchPriority when the view we care about appears, and call removeViewForTouchPriority when the view disappears or dealloc, in viewDidAppear/viewDidDisappear/dealloc of ViewControllers, so _touchView in ChunyuWindow is NULL, and it is the same as UIWindow, having no side effects.