I've a scrollview that has a UIView on it and on those Views, there's a UIImageView on it, three UILabel on it, I want to enable user Interaction on it, but wouldn't work. I've enabled setUserInteraction for both the UIView, UIScrollView, UILabels, UIImageView none is Responding to click actions at all. The layout look like the Image Below....
implement
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
so the gestures of the uiscroll view won't conflict with the subview's recognisers
basically what happens is that the UIScrollView won't pass the events to its subviews because the default of the above method is to return NO
This sounds too easy to be the problem, but I've made the following mistake: Everything is set just right, but I did not drag out one of the SentEvents like TouchUpInside to an action in the implementation.
check this way,
1> first check whether your view controller respond to UIGestureRecognizerDelegate this way
#interface RootViewController : UIViewController<UIGestureRecognizerDelegate>
2> then in design check you map scrollview property and delegate properly
3> apply this code in viewDidload
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapditected)];
tapGesture.delegate = self;
// prevents the scroll view from swallowing up the touch event of child buttons
tapGesture.cancelsTouchesInView = NO;
[self.scroller addGestureRecognizer:tapGesture];
4> check you apply this code
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
5> if all goes wll then this method should detected
-(void)tapditected{
}
Related
When I tap on a UIButton, a UIView MyView appear from the bottom a cover a third of the screen. I would like that when I tap somewhere outside this view, it disappears.
I thought about adding another transparent UIView right under MyView and add a tab gesture on it with the dismiss function but I'm sure there is something cleaner than this.
So I thought about adding the tap gesture MyTapGesture to dismiss MyView on self.view of the UIViewController. The problem is that outside this view, I have other UIControls and gestures that capture also any touch at the same time than MyTapGesture.
How can I make MyTapGesture the priority gesture outside MyView and ignore all other gesture, taps, etc...?
You may have to use the gesture delegate methods to handle two tapGestureRecognizer activate the one you need depending on scenario
#pragma mark - UIGestureRecognizerDelegate methods
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([tapGestureRecognizer1 isEqual:gestureRecognizer]) {
return [tapGestureRecognizer2 isEqual:otherGestureRecognizer];
}
if ([tapGestureRecognizer2 isEqual:gestureRecognizer]) {
return [tapGestureRecognizer1 isEqual:otherGestureRecognizer];
}
return NO;
}
Is there a simple solution to adding multiple UITapGestureRecognizers? I have a table view header which contains a UIImageView. Around the image view edges is clear space for the header. What I am trying to achieve is add a tap method for the header and tap method for the image view. But adding one to the header uses the entire header, including the image view. Is there a way to separate them?
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
UIView *header = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 250)];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(35, 10, 250, 250)];
_imageView = imageView;
_imageView.image = imageData;
UITapGestureRecognizer *headerTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(headerTapped:)];
_headerTap = headerTap;
UITapGestureRecognizer *imagetap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(imageTapped:)];
_imagetap = imagetap;
[header addGestureRecognizer:_headerTap];
[_imageView addGestureRecognizer:_imagetap];
[header addSubview:_imageView];
return header;
}
Make a transparent button covering the entire header.
Put the image view above it and cover that with another transparent button.
You can accomplish this by listening to the delegate methods of the gesture recognizer. Depending on how your views are set up you can use
(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
to see decide if you want your recognizer to fire. For instance We have an app with a drop down tableview to perform selections. We installed a two recognizers, one on the window so we can 'roll up' the drop down when the user taps outside of it, and one on the 'button' which is just the contents of a cell. We use this method to determine if the touch was outside of our visible tableviews bounds an if so we dismiss it.
The other relevant delegate method is
(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
From your description this seems like the best to use. From this you can tell your headers gesture recognizer not to fire alongside the one on your image view. For example
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (gestureRecognizer == self.headerGestureReconizer && otherGestureRecognizer == self.imageViewGestRecognizer) {
return NO;
}
return YES;
}
You can also set up dependencies within gesture recognizers via the instance method (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer. This is most useful when you have something like a single tap and a double tap recognizer on the same view and isn't what you want in this situation.
I have created a customViewController to act as a customActionsheet. In this customViewController I have a UIView as the main view (self.view) and an IBOutlet UIView that is the custom action sheet (actionSheetView). What I am trying to do is make this custom action sheet act like a regular actionsheet where if you tap in the dark area, in my case the view with blackColor background and alpha 5.0. This is what I have:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(slideOut)];
tapGesture.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapGesture];
The problem with this is that the subview, the custom action sheet view, also gets the tapgesture so tapping anything on the actionSheetView will get the tap gesture. I have tried a few things like - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch and self.actionSheetView.userInteractionEnabled = NO; but both do not seem to work. Anyone have any idea of how I can make the self.view tappable but disable that gesture for self.actionSheetView? Any tips, guidance, or help is greatly appreciated. Thanks in advance.
I was working on this same style of system. I found it works if you:
Add a new UIView as a subview of the main UIView.
Create another UIView where you want the custom UI (could be a table like an action sheet, a picker, etc). Make sure this shows above the UIView in step 1.
Register the UITapGestureRecognizer on the UIView from step 1.
(Optional) Add extra buttons (e.g. "Cancel" and "Done") and set up a delegate that your custom controller fires.
The main UIView (self.view) should be opague, clear color with alpha of 1. The full subview (see step 1) can be any color (I used light gray color), but adjust the alpha value (0.5 for me).
Unfortunately I can't post an image because I don't have enough rep on the site yet.
If you're using IB and having trouble receiving taps, check under the Attributes Inspector (under the view section) to make sure that "User Interaction" is enabled.
You need to set the delegate
tapGesture.delegate = self.actionSheetView
//actionSheetView.m
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return NO;
}
I've got a view hierarchy that looks like that
UIScrollView
|
+- UIView
|
+- UITextField
+- UITextField
+- UIButton
What I want is for user which tapped one of the text fields and sees the keyboard on the screen to be able to tap on an "empty space" of UIView to hide keyboard. So, I don't want, for instance, an event from UIButton to bubble up to UIView (that's exactly what happens if I add UITapGestureRecognizer to UIView).
How can I achieve the desired functionality?
In your viewDidLoad method add this gesture recognizer:
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
gestureRecognizer.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:gestureRecognizer];
Then add the dismissKeyboard method:
- (void) dismissKeyboard{
[YOURFIELDHERE resignFirstResponder];
}
You also need to add this to make it so the buttons are still clickable and not overridden by the gesture recognizer:
gestureRecognizer.delegate = self; // in viewDidLoad
<UIGestureRecognizerDelegate> //in your header file
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIButton class]]){
return NO;
}
return YES; // handle the touch
}
I encounter this same problem and solve it with a naive solution.
Change the View from an instance of UIView to an instance of UIControl so that it can handle touch events.
Create an IBAction method in the View Controller that handles the touch event. In this case, we will resign any first responder from the view's subviews.
- (IBAction)backgroundTapped:(id)sender
{
[contentView endEditing:YES];
}
contentView is just the instance variable pointing to the View. You can name it anything you want. When you passed the message endEditing to the View, it essentially tells its subviews to resign first responder, thus dismissing the keyboard.
Connect the target (View) and action (IBAction method you just created) via Interface Builder, by opening the connection inspector of the View, select Touch Up Inside and drag it to the File's Owner object, then select the name of the method.
Hopefully it helps.
I know it's a little late, but a quick, simple solution is the following:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
}
It gets called if you tap on any empty space.
Mike Z's answer is good. But I think the "if condition" below would be easier and simple in UIGestureRecognizerDelegate when you use Mike Z's answer.
Especially when the subviews are not only a button type, they may also be UITableViewCell, Custom View, etc.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return touch.view == yourEmptySpaceView;
}
I have set up some gesture recognition in an app that I'm building. One of the gestures is a single finger single tap, which hides the toolbar at the top of the screen. Works great except for one thing: a tap on a link causes the toolbar to go away, too.
Is it possible to detect a tap that was not a tap on a link? Could I do this by seeing where the tap occurred, and only take action if it didn't occur on an html link? Is this is possible, a pointer to how to determine if a link was tapped would be helpful.
Per Octys suggestion, I did attempt to wrap the UIWebView inside a UIView. I'm using interface builder, so I inserted a view in the hierarchy, and made the UIWebView a "child" of the new UIView. The hierarchy looks like this now:
I added an IBOutlet for the view in my view controller, and linked it up in interface builder.
I changed the gesture recognizer setup to look like this:
UITapGestureRecognizer* singleTap=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTouchesRequired=1;
singleTap.delegate=self;
[self.UIWebViewContainer addGestureRecognizer:singleTap];
[singleTap release];
This code resides in viewDidLoad.
As before, the code correctly sees a single finger single tap, but a tap on a link in the UIWebView also causes the toolbar to go away. I only want the toolbar to go away if a link was NOT tapped.
Anyone have any suggestions?
Thank you.
Chris
Thanks
Chris
Try wrapping your UIWebView in a UIView container and set your gesture recognizers on the container view. Touch events that are not handled by the UIWebView will be passed up the view hierarchy and be intercepted by your container view, assuming it implements the appropriate handlers (and it is these handlers that should implement the code for hiding the toolbars...).
OK, so one "hack-ish" workaround is to make the view controller which houses the UIWebView a delegate of the gesture recognizer that you instantiate(UIGestureRecognizerDelegate) I am usually not a fan of solutions like this one, but...
Assign the gesture recognizer to the view that wraps you web view, and set it's delegate to self.
then in the delegate method gestureRecognizer:shouldRecieveTouch method, set the state to indicate the there was a tap event,
Return NO from the delegate method so the event propagates down the responder chain to the UIWebView.
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
_userTapped = YES;
[self performSelectorOnMainThread:#selector(hideMenuIfNotLink) afterDelay:??.?];
//??.?? amount of time to lapse to see if shouldStartLoadWithRequest gets called.
return NO;
}
-(void)hideMenuIfNotLink{
if(_userTapped)
//hideMenu
}
Now, in your UIWebViewDelegate shouldStartLoadWithRequest (which gets called when a user has in fact clicked a link)
if(_userTapped){
_userTapped = NO;
//possibly code to reshow or verify keep showing menu
}
You can use the UIWebViewDelegate protocol's -webView:​shouldStartLoadWithRequest:​navigationType: method.
If the navigationType is UIWebViewNavigationTypeLinkClicked, you can get the URL for the click by checking [request URL].
I've been looking for the same thing and found this: There is an iOS specific property that disables the callout when you hold your finger on a link. You add this into the styling (CSS) of your urls.
-webkit-touch-callout: none;
This worked for me.try adding the below line of code
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
I was having the same problem. This solution worked for me:
1) make sure to add the protocol to your interface: UIGestureRecognizerDelegate
for example:
#interface ViewController : UIViewController _SlideViewProtocol, UIGestureRecognizerDelegate_
2) add this line of code
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
}
3)
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(nextSlide)];
swipeGesture.numberOfTouchesRequired = 1;
swipeGesture.direction = (UISwipeGestureRecognizerDirectionLeft);
swipeGesture.cancelsTouchesInView = YES;
[swipeGesture setDelegate:self];
[self.view addGestureRecognizer:swipeGesture];