iOS问题解决(二):自定义UIView不响应touchesBegan事件

iOS开发中会使用到自定义UIView,下面是我在学习过程中写的一个自定义UIView:

#import "BNRHypnosisView.h"

@interface BNRHypnosisView()

@property(nonatomic, strong) UIColor *circleColor;

@end

@implementation BNRHypnosisView

- (void)setCircleColor:(UIColor *)circleColor {
    _circleColor = circleColor;
    [self setNeedsDisplay];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        self.circleColor = [UIColor lightGrayColor];
        //self.userInteractionEnabled = YES; //开启用户交互仍然不能响应touchesBegan事件
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    CGContextRef cgContext = UIGraphicsGetCurrentContext();

    CGRect bounds = self.bounds;
    CGPoint center;
    center.x = bounds.origin.x + bounds.size.width / 2.0;
    center.y = bounds.origin.y + bounds.size.height / 2.0;

    float maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0;

    UIBezierPath *path = [[UIBezierPath alloc] init];
    
   for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -=     20) {
        [path moveToPoint:CGPointMake(center.x + currentRadius, center.y)];
        [path addArcWithCenter:center radius:currentRadius startAngle:0.0   endAngle:M_PI*2.0 clockwise:YES];
    }

    [self.circleColor setStroke];

    path.lineWidth = 10.0;

    [path stroke];


    CGContextSaveGState(cgContext);
    CGContextSetShadow(cgContext, CGSizeMake(4, 7), 3);

    UIImage *logoImage = [UIImage imageNamed:@"logo.png"];

    [logoImage drawInRect:rect];

    CGContextRestoreGState(cgContext);
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent   *)event {

    NSLog(@"%@ was touched", self);

    float red = (arc4random() % 100) / 100.0;
    float green = (arc4random() % 100) / 100.0;
    float blue = (arc4random() % 100) / 100.0;

    UIColor *randomColor = [UIColor colorWithRed:red
                                       green:green blue:blue alpha:1.0];
    self.circleColor = randomColor;
}

@end

在AppDelegate中使用这个自定义UIView,代码如下所示:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    NSArray *windows = [[UIApplication sharedApplication] windows];
    for(UIWindow *window in windows) {
        if(window.rootViewController == nil){
            UIViewController *vc = [[UIViewController alloc]initWithNibName:nil
                                                                 bundle:nil];
            window.rootViewController = vc;
        }
    }

    CGRect firstFrame = self.window.bounds;
    BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:firstFrame];

   [self.window addSubview:firstView];


    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

看似很完美的代码,但是一运行,无法响应touchesBegan事件,开始以为是没有开启用户交互,加上开启用户交互self.userInteractionEnabled = YES,仍然没用,后来有人说是这个自定义UIView视图被遮挡,导致无法响应触摸事件,给了我开启视图调试器调试看看的建议,果然,开启视图调试器看到这个自定义UIView确实被遮挡了,如下图所示:

iOS问题解决(二):自定义UIView不响应touchesBegan事件_第1张图片
viewdebug.png

该怎么解决呢?有人说是[self.window makeKeyAndVisible]出了问题,他会把window的rootViewController放到最前面,但我想这肯定是没读懂官方文档对makeKeyAndVisible方法的解释,如下图所示:

iOS问题解决(二):自定义UIView不响应touchesBegan事件_第2张图片
makeKeyAndVisible.png

它是UIWindow对象的一个实例方法,是把当前window置于其他window的前面,也就是说是把整个包含了我的自定义UIView的window对象置于最前面,所以,即使注释掉这行代码,仍然无法解决我的自定义UIView被遮挡的问题。

那么问题出在哪里呢?对,问题就出在AppDelegate的下面这段代码中:

NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow *window in windows) {
    if(window.rootViewController == nil){
        UIViewController *vc = [[UIViewController alloc]initWithNibName:nil
                                                                 bundle:nil];
        window.rootViewController = vc; 
    }
}
iOS问题解决(二):自定义UIView不响应touchesBegan事件_第3张图片
rootViewController.jpeg

根据上图所示官方文档对rootViewController的说明,可以知道设置了window.rootViewController会给window设定一个content view。根据视图调试器显示出来的内容,这个content view应该也就是一个UIView。所以当这个自定义的UIView添加到self.window上,代码如下所示:

CGRect firstFrame = self.window.bounds;
BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:firstFrame];

[self.window addSubview:firstView];

这个自定义UIView就会被rootViewController设定的content view遮挡,就不能响应触摸事件了。

因此,解决这个问题修改后的关键代码如下所示:

CGRect firstFrame = self.window.bounds;
BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:firstFrame];

[self.window.rootViewController.view addSubview:firstView];

你可能感兴趣的:(iOS问题解决(二):自定义UIView不响应touchesBegan事件)