views:

281

answers:

3

I have a UIScrollView with subclassed UIImageViews in it. When one of the imageviews are clicked, I'd like the parent UIView (contains the scrollview) to receive the event in its

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

I can tell if the imageview was clicked by

if(CGRectContainsPoint(myScrollView.frame, location) == YES){...}

Assuming the imageview and scrollview are the same size. Or is there a better way to to know a particular imageview within the scrollview was tapped? The imageviews are created dynamically.

A: 

If the image views don't have any children, you can use the UIView method hitTest:withEvent:. It returns the farthest descendent of a UIView that contains a given touched point. So for example:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    CGPoint location = [[touches anyObject] locationInView:myScrollView];
    UIView *touchedView = [myScrollView hitTest:location withEvent:event];
    // ...
}
Tim
Where is touchesEnded located? If inside the parent UIView, it never fires when the UIImageView is tapped. It will fire if either the scrollview or uiview are tapped.
4thSpace
4thSpace: if so, that's correctable by subclassing the child instances of UIImageView to forward a touch event to `[self superview]` in `touchesEnded:withEvent:`. (I'd recommend disabling user interaction, but that breaks `hitTest:withEvent:` as well.)
Tim
Thanks. I've updated the OP to reflect my UIImageViews are subclassed. Your idea makes sense but touchesEnded:withEvent isn't firing in the subclassed UIImageViews.
4thSpace
+3  A: 

The approach I've used for this in the past is to fire off a notification when a subview has been touched, with the subview as the object posted with the notification. You can then have your container view listen for the appropriate notification, and perform whatever action is needed based on the UIView instance that was selected.

You'd post the notification within the subview's -touchesEnded:withEvent: method as follows:

[[NSNotificationCenter defaultCenter] postNotificationName:@"MySubviewWasTouched" object:self];

To set up listening for this notification, you'd place code like the following somewhere in the initialization of your view or view controller:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleSubviewTouch:) name:@"MySubviewWasTouched" object:nil];

remembering to remove the observer in your teardown code for the the view or controller.

Finally, you'd need to implement the method that processes the receipt of the notification (-handleSubviewTouch: in the example above):

- (void)handleSubviewTouch:(NSNotification *)note;
{
    UIView *subviewThatWasTouched = [note object];

    // Your touch-handling logic here
}
Brad Larson
This makes sense and I've added touchesEnded to my subclassed UIImageViews but it isn't firing. I didn't mention the UIImageViews are subclasses but I've updated the OP. Not sure if anything extra needs to be done for subclasses. I'm thinking not.
4thSpace
I see that Noah has pointed out the userInteractionEnabled property, which is often the problem with UIImageViews and touch handling.
Brad Larson
+1  A: 

Note that UIImageView ignores touches (or rather, lets them pass through to its superview) by default. Make sure you set your image views' userInteractionEnabled property to YES.

Noah Witherspoon