Search code examples
iosobjective-cuiviewtouchesbegan

UIView not getting touchesbegan called


There are a number of other issues for this but none of the solutions seem to be working for me. I'm very new to iOS - currently working on a problem from the Big Nerd Ranch iOS Programming book.

Most of the SOs I found said the issue ended up being userInteractionEnabled = YES was missing. Or the view's background was set to transparent. But removing the transparent background and setting userInteractionEnabled = YES did not result in the event firing. Any ideas what I'm missing?

AppDelegate.m:

#import "AppDelegate.h"
#import "BNRHypnosisView.h"
#import "ViewController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


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

    CGRect firstFrame = self.window.bounds;

    BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:firstFrame];
    firstView.userInteractionEnabled = YES;

    ViewController *controller = [[ViewController alloc] init];
    [self.window setRootViewController:controller];
    [self.window addSubview:firstView];

    self.window.backgroundColor = [UIColor whiteColor];

    [self.window makeKeyAndVisible];

    return YES;
}

BNRHypnosisView.m:

#import "BNRHypnosisView.h"

@interface BNRHypnosisView()

@property (strong, nonatomic) UIColor *circleColor;

@end

@implementation BNRHypnosisView
-(void)drawRect:(CGRect)rect {
    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];
    }

    path.lineWidth = 10;

    [self.circleColor setStroke];

    [path stroke];
}

-(instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        self.circleColor = [UIColor lightGrayColor];
    }
    return self;
}

-(void)touchesBegan:(NSSet<UITouch *> *)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;
}

Screenshot of app: enter image description here

Screenshot of view debuggerenter image description here


Solution

  • You're adding your BNRHypnosisView as a subview of the window. Later, when the window is about to appear on screen, it adds its root view controller's view as another subview, in front of your hypnosis view. You can see this in the view hierarchy, where it shows a plain UIView after your BNRHypnosisView. A view later in the list is “on top of” or “closer to the screen than” a view earlier in the list.

    Try this:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        self.window.backgroundColor = [UIColor whiteColor];
    
        ViewController *controller = [[ViewController alloc] init];
        [self.window setRootViewController:controller];
    
        BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:controller.view.bounds];
        firstView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        firstView.userInteractionEnabled = YES;
        [controller.view addSubview:firstView];
    
        [self.window makeKeyAndVisible];
        return YES;
    }