UIGestureRecognizer subView recognizer problem

蓝咒 提交于 2020-01-13 03:57:07

问题


The title is hard . The the main case is like this

UIView *superView = [[UIView alloc] initWithFrame:CGRectMake(0,0,400,400)];
UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(-200,-200,400,400)];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
[subView addGestureRecognizer:tapGesture];
[superView addSubView:subView];

OK , you will find that the tap gesture will take effect when you click the area in (0,0,200,200) , if you click the point (-150,-150) the tap gesture will not take effect.

I don't know whether the click outside the superView bounds to cause this problem or not.

Anyone have any idea how to fix this?


回答1:


The only workaround I've found for case like that is to create an instance of a view that is transparent for touches as main view. In such case inner view will respond to touches as it fits bounds of main. In the class I've made from different examples found in the net I can control the level of "touch visibility" like so: fully visible - all of the touches end up in the view. only subviews - the view itself invisible, but subviews get their touches. fully invisible - pretty self explanatory I think :)

I didn't try to use it with gesture recognizers, but I don't think there will be any problem, as it works perfectly with regular touches.

The code is simple...

TransparentTouchView.h

#import <UIKit/UIKit.h>

typedef enum{
    TransparencyTypeNone = 0,         //act like usual uiview
    TransparencyTypeContent,          //only content get touches
    TransparencyTypeFull              //fully transparent for touches
}TransparencyType;

@interface TransparentTouchView : UIView {
    TransparencyType      _transparencyType;
}

@property(nonatomic,assign)TransparencyType transparencyType;

@end

TransparentTouchView.m

#import "TransparentTouchView.h"


@implementation TransparentTouchView

@synthesize 
transparencyType = _transparencyType;

- (id)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    // UIView will be "transparent" for touch events if we return NO
    switch (_transparencyType) {
        case TransparencyTypeContent:
            for(UIView* subview in self.subviews){
                CGPoint p = [subview convertPoint:point fromView:self];
                if([subview pointInside:p withEvent:event]){
                    return YES;
                }
            }
            return NO;
            break;
        case TransparencyTypeFull:
            return NO;
        default:
            break;
    }
    return YES;
}

@end

I believe that you can accomodate it to your needs.




回答2:


To allow subviews lying outside of the superview to respond to touch, override hitTest:withEvent: of the superview.

Documentation on Event Delivery

Touch events. The window object uses hit-testing and the responder chain to find the view to receive the touch event. In hit-testing, a window calls hitTest:withEvent: on the top-most view of the view hierarchy; this method proceeds by recursively calling pointInside:withEvent: on each view in the view hierarchy that returns YES, proceeding down the hierarchy until it finds the subview within whose bounds the touch took place. That view becomes the hit-test view.

  1. Create a subclass of UIView.
  2. Override hitTest:withEvent.
  3. Use this UIView subclass for the superview.

Add method below in subclass:

(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    NSEnumerator *reverseE = [self.subviews reverseObjectEnumerator];
    UIView *iSubView;

    while ((iSubView = [reverseE nextObject])) {

        UIView *viewWasHit = [iSubView hitTest:[self convertPoint:point toView:iSubView] withEvent:event];
        if(viewWasHit) {
            return viewWasHit;
        }

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

Note: Reverse enumerator used since subviews are ordered from back to front and we want to test the front most view first.



来源:https://stackoverflow.com/questions/6060591/uigesturerecognizer-subview-recognizer-problem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!