I have a view that has a UITableView as a subview, and it completely covers the parent view. When I try to implement touchesBegan for the parent view, I'm noticing the method isn't being called at all. Is there anyway to override this behavior?
Actually there is a way to override this behavior. You need to extend each child object that are blocking the parent view and override touchesBegan method like this:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self.nextResponder touchesBegan:touches withEvent:event];
}
For example, if you have a UIButton inside a UIScrollView which is inside a UIView then you need to create two custom classes. One extending UIButton and other extending UIScrollView. In each of these custom classes you need to add the above method definition. After these changes you will be able to receive touchesBegan event in parent UIView.
The touchesBegan method has to do with the frame of the parent view. If the frame isn't visible for the parent view and is totally enclosed by the subviews, the parent view won't receive touches.
You can also set:
[theViewThatIsCoveringParent setUserInteractionEnabled:NO];
This way all touches will be caught by the parent.
Do this: Why isn't my UIViewController in the responder chain for its view?
In short:
Link your views to your controller.
Add a property called nextResponderPlusSomething (there is already a nextResponder) inside the view which is getting touches
In viewdidload set this property to the controller (self)
Inside the touchesBegan add a call to the nextResponderPlusSomething:touchesBegan
Implement this event on controller, sending the event to the view that you want to be called.
Related
Possibly a duplicate, but I couldn't find an exact answer to my problem searching SO tonight...
I have a UIButton which contains a UIScrollView, so the button is the superview.
All I want to do is pass a single-tap event from the UIScrollView subview to the UIButton superview, and have the UIButton handle it as it would if the user tapped the button directly.
Setting the scroll view's userInteractionEnabled property to NO won't work for me because there is content the user can scroll. Doing so would defeat the purpose of the scroll view.
Is this possible? Thanks!
Like huoxinbird said, it's definitely not common to lay your views like that.
In the case where you are solidly adamant about this, you could use UITapGestureRecognizer and have it call the button's target and selector.
If you wanted to include the button highlight and such, then you may have to subclass UITapGestureRecognizer and forward the touchesEnded to the button.
Create a subclass of scrollview and override
-(BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
return YES;
}
Also subclass the uibutton(Your superview) and handle touches in touches began.
Usually you don't put scrollview within a button. Instead consider using a UIView as the superview of scrollview. Or tell us more about your use case, so I can understand why you have to design in this way.
I have a UIScrollView ontop of my UIViewController recreating an effect like in the Gowalla iPhone app when you're on a spot's page. Under my scroll view I have a button that I want to be able to perform it's action even when the scroll view's frame covers it up (where it's ontop of the button, the scroll view's clear). How would I do something like this? Is it possible? (it has to be, Gowalla [somehow] did it)
As for me, I will transfer touch event to another view by override following methods.
– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:
Like this way,
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// pass touch event by default implement.
[super touchesBegan:touches withEvent:event];
// redirect the touch events.
[anotherView touchesBegain:touches withEvent:event];
}
hitTest:withEvent: is used to decide which view should response touch event on the view hierarchy tree. If the view doesn't want to response touch event, it will return nil in hitTest. As result the above touch event methods won't be called.
I have no idea what this "Gowalla" app might do; hopefully, your description of "a button behind the scroll view, that you can touch 'through' the scroll view" is accurate.
If your button behind the scroll view can be sized to fill the entire contentSize area of the scroll view without screwing up your interface, the easiest solution would be to just put it inside the scroll view (under all the other views) and do just that.
Otherwise, your best bet is probably to create a custom view with a clear background to be placed in the scroll view as above. The easy solution is to have the custom view (probably a UIControl) just do whatever touching the button does. If that's not possible for some reason, your best option would be to override hitTest:withEvent: on the custom view to return the underlying button. I'd be wary of overriding hitTest:withEvent: on the scroll view itself, as that might interfere with scrolling.
Try adding the button on top of the scroll view. The only problem with that is if you hit the button, you will not be able to interact with the scrollView, but it will still be visible.
I have a UIViewController and an associated with it UIView. The UIView has a number of subviews.
How to handle touch event inside a specified rectangle in my UIViewController subclass?
This handling should be transparent: UIView and its subviews should still receive their touch events even if they intersect with the specified rectangle.
P.S.
Overriding touchesBegan in the view
controller doesn't work. Inner views
doesn't pass events through.
Adding a custom
button to the end of UIView subviews
list also doesn't work. Inner
subviews doesn't receive touch
events.
touchesBegan/touchesMoved/touchesEnded is probably the way to go. Depending on exactly what you are trying to do, UIGestureRecognizer may also be an option.
To make sure subviews pass events up, set userInteractionEnabled to YES on the subviews.
UIView sets this to YES by default, but some subclasses (notably UILabel) override this and set it to NO.
Just because the views don't pass events through by default doesn't necessarily mean that's the way it has to be.
You could subclass the views that you are using and have them pass the events onto the view controller.
Another idea is to literally have a transparent handler on top of all of your views. That is, have a transparent UIView that sits above your views, handling touch events but also passing them through. I have no idea if this works in practice, but it sounds like it would.
Your views, and their controllers can handle a touch using touchesBegan, touchesEnded or touchesMoved. Within touchesBegan as an example you can then choose to pass the event to
the next responder in the responder chain. This way each of your views will get a chance to do something based on the touch event.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//do something here and then pass the event on
[self.nextResponder touchesBegan:touches withEvent:event];
}
Title more or less says it all. In response to a touchesBegan event, my UIViewController recolours itself and adds some subviews.
It never receives the touchesEnded. I guess because the added subviews are somehow intercepting the event. I tried calling resignFirstResponder on the subviews to no avail.
The code works fine when I don't add the child views and the touch events are called as normal.
Any ideas?
Thanks
EDIT: Bit of detail and how I fixed it.
Basically I had a master view with some subviews, when I touched the subview, the event would be passed through to the master view, however, on this event I was removing the subviews and adding new ones in their place. The fact that the touch originated on a subview which no longer existed meant that the rest of the touch was lost.
I fixed this by overriding hitTest:withEvent in my master view, to stop touches ever getting tested against the subviews
Did you try to set the userInteractionEnabled property to NO for the subview before adding it as a subview ?
You're going to need pass the touch from the subview onto the superview using something like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
}
I have four imageview in sequence on a screen setting with custom background images. When user touches an imageview (for ex: user touches second imageview), can i get touch notification with which imageview is touched?
I have array of imageview already and placed, and i have to implement touch event and under that identify which imageview is selected.
I want help from some one who can have suggestions to develop this, please suggest me?
thanks.
Using UIButtons as replacements for your UIImageViews is a great idea that Morion mentioned as you can just drag a connection from each button to an outlet in your view controller and handle the action. You can set the background image on the buttons as you are doing currently with the UIImageViews. Set your button type to custom and you'll be good to go.
If, however, you are set on using UIImageView, you will have to subclass UIImageView and override the touch methods you want to intercept. For example:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Call super to make sure you don't lose any functionality
[super touchesBegan:touches withEvent:event];
// Perform the actions you want to perform with the tap.
}
you can use custom buttons instead of UIImages. so it will be easy to find which of them was pressed.