1

Here's my view hierarchy: parentView (UIView) has a UIImageView as its subview which in turn has a UIButton as its subview.

left = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"left.png"]];
left.userInteractionEnabled = YES;
[parentView addSubview:left];

back = [UIButton buttonWithType:UIButtonTypeCustom];
[back setImage:[UIImage imageNamed:@"Arrow-left.png"] forState:UIControlStateNormal];
[back addTarget:self action:@selector(back:) forControlEvents:UIControlEventTouchUpInside];
back.showsTouchWhenHighlighted = YES;
[left addSubview:back];

Everything shows up properly but the button does not respond to touches. It does respond if I move its frame out of the UIImageView's frame to somewhere else and set it as a subView to the parentView (UIView). But here's the thing.

Even if I set to parentView's subView the button does not respond if it is within the UIImageView's frame area. The userInteractionEnabled property has been already set to YES for the image view. Any idea what's going on?

Bourne
  • 10,094
  • 5
  • 24
  • 51
  • 1
    What is the code for **back:**. Have you placed an `NSLog` there to see if in fact it is triggering? – WrightsCS Jul 25 '12 at 14:54
  • Could you try adding the button to the `parentView` instead of `left`? – Eric Brotto Jul 25 '12 at 15:04
  • @EricBrotto It's already there in my question. I tried doing that and it works only as long as the button does not fall in the imageview's frame area. – Bourne Jul 25 '12 at 15:08
  • @WrightsCS The question very much says that it triggers when placed outside the image view's frame area. – Bourne Jul 25 '12 at 15:08
  • Dumb question, but is the button underneath the imageView? Could you place it on top? – Eric Brotto Jul 25 '12 at 15:17
  • @EricBrotto Checked that as well as the first step :) I am adding the subviews in proper sequence. The button is above the UIImageView, which is above the UIView. – Bourne Jul 25 '12 at 15:20
  • Hmmm... my first guess is that something is being added elsewhere that you may have overlooked. Could you link to the `.m` file? – Eric Brotto Jul 25 '12 at 15:22

5 Answers5

1

UIImageView turns off userInteraction - turn it on and the button will work.

EDIT:

So I used your code almost exactly as written - the one red herring is that you said it all appears fine. For me, the custom button had a frame of 0,0,0,0 so I saw nothing. When I set the frame it all worked perfectly:

    UIButton *back = [UIButton buttonWithType:UIButtonTypeCustom];
    UIImage *image = [UIImage imageNamed:@"46-truck.png"];
    assert(image);

    [back setImage:image forState:UIControlStateNormal];
    [back addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
    back.showsTouchWhenHighlighted = YES;
    back.frame = (CGRect){ {0,0}, image.size};

NSLog(@"FRAME: %@", NSStringFromCGRect(back.frame) );
    [imageView addSubview:back];

So, if you need to probe the superviews during run time to figure out what is what, you can use this code below. [UIView dumpSuperviews:back msg:@"Darn Bark Button"];

@interface UIView (Utilities_Private)

+ (void)appendView:(UIView *)v toStr:(NSMutableString *)str;

@end

@implementation UIView (Utilities_Private)

+ (void)appendView:(UIView *)a toStr:(NSMutableString *)str
{
    [str appendFormat:@"  %@: frame=%@ bounds=%@ layerFrame=%@ tag=%d userInteraction=%d alpha=%f hidden=%d\n", 
        NSStringFromClass([a class]),
        NSStringFromCGRect(a.frame),
        NSStringFromCGRect(a.bounds),
        NSStringFromCGRect(a.layer.frame),
        a.tag, 
        a.userInteractionEnabled,
        a.alpha,
        a.isHidden
        ];
}

@end

@implementation UIView (Utilities)

+ (void)dumpSuperviews:(UIView *)v msg:(NSString *)msg
{
    NSMutableString *str = [NSMutableString stringWithCapacity:256];

    while(v) {
        [self appendView:v toStr:str];
        v = v.superview;
    }
    [str appendString:@"\n"];

    NSLog(@"%@:\n%@", msg, str);
}

+ (void)dumpSubviews:(UIView *)v msg:(NSString *)msg
{
    NSMutableString *str = [NSMutableString stringWithCapacity:256];

    if(v) [self appendView:v toStr:str];
    for(UIView *a in v.subviews) {
        [self appendView:a toStr:str];
    }
    [str appendString:@"\n"];

    NSLog(@"%@:\n%@", msg, str);
}

@end
David H
  • 40,852
  • 12
  • 92
  • 138
  • If you read the code and the last part of the question, he has it enabled. **`left.userInteractionEnabled = YES;`** – WrightsCS Jul 25 '12 at 14:52
  • Ah yes, I jumped to conclusions and did not see that line :-(. Its just so common. Anyway, does the parent view have userInteractionEnabled? I have never added a button to a imageView, but I have added a gesture recognizer. – David H Jul 25 '12 at 14:57
  • I have set the frames properly in another method that I use to set frames for all views in the screen. So it appears at the proper frame as well. – Bourne Jul 25 '12 at 15:16
  • Well, my point is - I created a UIImageView, added it to the view, then in code created the button EXACTLY as you did, added it to the ImageView, and it works perfectly. So there is something more to this than you have exposed. Another view overtop the imageView blocking events, etc. Dump the view hierarchy - I'll add code to my answer. – David H Jul 25 '12 at 15:36
0

Maybe

parentView.userInteractionEnabled = YES;

Or parent view frame are to small and can`t hold button or image view. Check size of parent view;

Moonkid
  • 881
  • 7
  • 17
  • 1
    parentView is a `UIView` so would have that set by default, also it seems the button works when not overlapped with the `UIImageView`. – Autonomy Jul 25 '12 at 15:13
0

I've had this happen before.. I think it was a super view swallowing the event.

I know you've stated that adding it to the parentView only works if it doesn't overlap with the image view. If you disable user interaction on the image view, does the button event trigger consistently when added to the parentView?

Autonomy
  • 402
  • 4
  • 13
  • Yes. it works with the imageView removed. It only doesn't work when it is UIView->UIImageView->UIButton in hierarchy. Regardless of whether UIButton is a subView to the UIImageView or UIView. – Bourne Jul 25 '12 at 15:32
  • Just to be clear, when you say it 'only doesn't work when' it is a subview of UIImageView (UIView->UIImageView->UIButton), you also mean it doesn't work when it is a subview of UIView (UIView->UIImageView & UIView->UIButton)? EDIT: It's just that your last comment != what you've said in the OP. – Autonomy Jul 25 '12 at 15:35
  • 1
    Yes. Doesn't work in both cases. In the second case it works only if the button's frame is set out of the Imageview's – Bourne Jul 25 '12 at 15:38
  • Sounds to me like the `UIImageView` is eating the touch event before the `UIButton` gets it. I can't remember how to fix that though, sorry, and as you've stated you have the order correct, so I don't know why the imageview would eat the event if the button is on top of it. You could try explicitly moving the `UIButton` to the front; `[parentView bringSubviewToFront:back]`. – Autonomy Jul 25 '12 at 15:41
  • I have to add that there's another part in my app with a similar scenario but its just a UIImageView with a UIButton subview. That works properly with userInteractionEnabled set to YES. It stops when a UIView is behind that UIImageView. – Bourne Jul 25 '12 at 15:43
0

You actually need to set userInteractionEnabled = NO to allow the touches to pass through.

Taken from here.

Community
  • 1
  • 1
Eric Brotto
  • 53,471
  • 32
  • 129
  • 174
  • Ah.. doesn't work. I am adding the views in proper hierarchy. I even tried setting zPositions for using the layers for the view properly. Doesn't work even then. – Bourne Jul 25 '12 at 15:41
-1
left.userInteractionEnabled = YES;

put this line in the end.

NSPunk
  • 502
  • 4
  • 14