Hi I have a UIView who's alpha is 0.7 and below it are some UITextFields. I don't want it to call touches events while keeping touches events. I tried using
[lightBoxView setUserInteractionEnabled:NO];
But now the UITextFields can become active or first responder. How can I disable it from calling touch events as well as not passing touches to others?
You also need to set the userInteractionEnabled = NO for all the subviews as well.
Try this,
[[lightBoxView subviews] makeObjectsPerformSelector:#selector(setUserInteractionEnabled:)
withObject:[NSNumber numberWithBool:NO]];
This will call setUserInteractionEnabled: on all direct subviews of lightBoxView and set it to NO. For a more complex subview hierarchy you will have to recursively loop through all the child views and disable the user interaction on each one. For this you can write a recursive method in a UIView category. For more details about this category method take a look at this answer.
Hope that helps!
You can remove those control from tough gesture delegate method.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UITextFiled class]])
{
return NO;
}
else
{
return YES;
}
}
Related
I have a swipe gesture attached to a UIView that doesn't seem to be registering when the swipe is on top of it's subviews.
One of solution is to check is gesture point inside your subview or not,
there is a useful C function:
/* Return true if `point' is contained in `rect', false otherwise. */
bool CGRectContainsPoint(CGRect rect, CGPoint point)
that you can use like this:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return CGRectContainsPoint(subview.frame, [touch locationInView:self.view]);;
}
The other solutions should work, but a potentially easier one is to set subview.userInteractionEnabled = false in the subview if it doesn't have its own event handlers.
Let's say A is the root UIView which you want to receive swipes, and B is a subview of A that you don't really want to receive swipes.
if you do not want to receive any gestures on B, you can userInteractionEnabled = false on it
if you still want to receive some gestures on B (but not a swipe)
you must subclass B so that you can implement this method, and implement this method in B
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([gestureRecognizer isKindOfClass:UISwipeGestureRecognizer]) {
return NO;
}
return YES;
}
You can also see how you may get a wide range of functionality from implementing gestureRecognizer:shouldReceiveTouch:
My UIScrollView inside a nested UITableView, in which UITableView has a left row pop-up menu of gestures, and now the two views of the gesture conflict. Now the question is: how to solve this problem without changing the UITableView ?
PS: I have been set UIScrollView ScrollEnabled=false
Your question is different but as you agree that your main problem is conflict between the gestures, that means you are not able to differentiate between gesture of two views,
To solved there are two ways, you need to receive gesture based on condition in gestureRecognizer delegate method, you can either check the class which received the gesture or by checking class or by tag
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
{
if([touch.view class] == [UITableView class]){
return NO;
} else if (touch.view.tag == 100) {
return NO;
} else if ([NSStringFromClass([touch.view class]) isEqualToString:#"UITableViewCellContentView"]) {
return NO;
}
return YES;
}
What this delegate would do is, it will call the gesture handler method only for the view which you want to handle gesture and also you can differentiate between the gesture recogniser.
I have added UIPanGestureRecognizer on the view of my UIViewController.
In this view (a calculator) are some UIButton triggered by the event .TouchUpInside.
The problem comes if I tap on the button and make a small pan at the same time (which might happen if you tap quickly a button and are moving to the next one at the same time). Then the pan gesture is triggered. I would like to avoid it when there is a tap on a button. But I would like to allow it if the tap takes too long (let say 0.3s is enough to trigger the pan gesture).
How can I achieve that?
Set the property cancelsTouchesInView of your gesture recognizer to NO.
Then your button should work properly.
You can use the delegate method like this-
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
if ([touch.view isKindOfClass:[UIButton class]]) {
return NO;
}
return YES;
}
There is a dirty solution. You can just grab it in a UIScrollView
I have a view with a UIToolbar with a few UIBarButtonItems and a UITableView containing some UITextFields.
I would like to dismiss the keyboard for a textfield with a tap anywhere. Therefore I added a TapGestureRecognizer to the view. To avoid that the TapgestureRecognizer handles taps on the UIBarButtonItems I added the following method (delegate is set).
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
UIView *view = touch.view;
while (view) {
NSLog(#"Class of view: %#", NSStringFromClass([view class]));
view = view.superview;
}
// Disallow recognition of tap gestures in the toolbar
if ([touch.view isKindOfClass:[UIToolbar class]]) {
return NO;
}
if ([touch.view.superview isMemberOfClass:[UIToolbar class]]) {
return NO;
}
return YES;
}
A UIBarButtonItem is not a view itself, but it has UIToolbar as its superview. When I use the above method, the check for isKindOfClass:[UIToolbar class] does not seem to work for all taps on the toolbar. However the check for the superview with isMemberOfClass:[UIToolbar class] works.
I don't understand this. Maybe someone can explain this behavior?
You shouldn't rely on the view hierarchy around private view classes. It could change at any time.
A better approach is to add the gesture to the table view (or other appropriate view which represents the area you're interested in). Just be sure to enable and disable the gesture at appropriate times so as not to block the usual table operation.
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;
}