Ok, I have a WKWebView with a big textarea inside it, and when I click on it, it fires this UIWebTouchEventsGestureRecognizer and shows the keyboard.
This behavior is correct. Problem is, when scrolling or panning from any other gesture, this UIWebTouchEventsGestureRecognizer is fired and the keyboard shows.
Is there any way to prevent that?
I'm using this to get the problematic gesture recognizer:
for (UIView* subview in self.subviews) {
// here comes the tricky part, desabling
for (UIView* subScrollView in subview.subviews) {
if ([subScrollView isKindOfClass:NSClassFromString(#"WKContentView")]) {
for (UIGestureRecognizer* gesture in [subScrollView gestureRecognizers]) {
if ([gesture isKindOfClass:NSClassFromString(#"UIWebTouchEventsGestureRecognizer")]) {
gesture.delegate = self;
gesture.delaysTouchesBegan = true;
gesture.delaysTouchesEnded = true;
[gesture requireGestureRecognizerToFail:scrollGesture];
}
}
}
}
}
requireGestureRecognizerToFail: doesn't work;
-(BOOL)gestureRecognizer:shouldRequireFailureOfGestureRecognizer:
also didn't work
The only thing that worked is returning false on this delegate method:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return false;
}
But obviously, now the keyboard will never show..
Resuming, I need the webview to get focus on taps, and to ignore pans and other gestures.
Any tips?
Did you this this one ?
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
Related
This is what I want to do
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view != self.myView) {
NSLog(#"we went with no");
//don't let anything that's not myView fire the gesture recognizer
return NO;
}
NSLog(#"we went with yes");
return YES;
}
The problem is the code always chooses the path of "we went with no" no matter where I actually tap. How do I fix my if check?
If you're finding that your gesture recognizer action is firing when you're tapping outside of a specific view, you should double-check that you added the gesture recognizer correctly.
[self.myView addGestureRecognizer:[[UIGestureRecognizer alloc] initWithTarget:self action:#selector(someAction:)]];
If you still experience incorrect action fires, you could check the touch location.
if (CGRectContainsPoint(self.myView.bounds, [gesture locationInView:self.myView]))
I am trying to handle tableViewCell's being tapped, but the problem is that this is a "temporary tableView". I have it coded so that it will appear while the user is editing a UITextField, but then I set up a gesture recognizer to set the tableview to hidden as soon as the user clicks somewhere away from the UITextField.
I have the gesture recognizer set up as follows:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[tap setCancelsTouchesInView:NO];
[self.view addGestureRecognizer:tap];
However, dismissKeyboard is called before didSelectRowAtIndexPath is called, and so the TableView that I want to handle the event on becomes hidden and therefore this function is never called.
My question is: Does anybody have ideas of how to get around this, so that didSelectRowAtIndexPath will execute before the tableView hides? I had one idea to somehow see if the tableView is where the tap is coming from, and if so, then don't execute the "hide tableView" line within dismissKeyboard. Is this possible?
Sorry, but I am new to iOS dev, so thank you for any advice!
You should be able to do this by making your view controller the tap gesture's delegate and denying it any touches that are inside the table view. Here is a starting point:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch
{
//Assuming your table view is a direct subview of the gesture recognizer's view
BOOL isInsideTableView = CGRectContainsPoint(tableView.frame, [touch locationInView:gesture.view])
if (isInsideTableView)
return NO;
return YES;
}
Hope this helps!
You could set yourself as a delegate to the UITapGestureRecognizer and cancel the gesture when the user taps within the tableView.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
//You can also (and should) check to make sure the gestureRecognizer is the tapGestureRecognizer
if (touch.view == tableView)
{
return NO;
}
else
{
return YES;
}
}
To better fit what you need, judge if your search bar is first responder.
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch
{
BOOL isInsideTableView = CGRectContainsPoint(yourTabelView.frame, [touch locationInView:gesture.view]);
if (isInsideTableView && ![yourSearchBar isFirstResponder])
return NO;
return YES;
}
I have a UIPanGuestureRecognizer added to the entire view using this code:
UIPanGestureRecognizer *pgr = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panAction:)];
[[self view] addGestureRecognizer:pgr];
Within the main view I have a UITableView which has this code to enable the swipe to delete feature:
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"RUNNING2");
return UITableViewCellEditingStyleDelete;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row >= _firstEditableCell && _firstEditableCell != -1)
NSLog(#"RUNNING1");
return YES;
else
return NO;
}
Only RUNNING1 is printed to the log and the Delete button does not show up. I believe the reason for this is the UIPanGestureRecognizer, but I am not sure. If this is correct how should I go about fixing this. If this is not correct please provide the cause and fix. Thanks.
From the document:
If a gesture recognizer recognizes its gesture, the remaining touches for the view are cancelled.
Your UIPanGestureRecognizer recognizes the swipe gesture first, so your UITableView does not receive touches anymore.
To make the table view receives touch simultaneously with the gesture recognizer, add this to the gesture recognizer's delegate:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
If you are using UIPanGuestureRecognizer for example to show side menu you might see some unwanted side effects when you just return YES in all cases as proposed in accepted answer. For example the side menu opening when you scroll up/down the table view (with additional very little left/right direction) or delete button behaving strangely when you open the side menu. What you might want to do to prevent this side effects is to allow only simultaneous horizontal gestures. This will make the delete button work properly but at the same time other unwanted gestures will be blocked when you slide the menu.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if ([otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
{
UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *)otherGestureRecognizer;
CGPoint velocity = [panGesture velocityInView:panGesture.view];
if (ABS(velocity.x) > ABS(velocity.y))
return YES;
}
return NO;
}
or in Swift:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
guard let panRecognizer = otherGestureRecognizer as? UIPanGestureRecognizer else {
return false
}
let velocity = panRecognizer.velocity(in: panRecognizer.view)
if (abs(velocity.x) > abs(velocity.y)) {
return true
}
return false
}
If the accepted answer does not work. Try adding
panGestureRecognizer.cancelsTouchesInView = false
Ensure you haven't added the gesture to the tableview directly. I added a pan gesture on the ViewController view and can confirm it works.
it means user can't pan and pinch simultaneously and pinch gesture stops pan one.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
This code is not working for me because it makes these gestures working simultaneously.
By default if I don't use this code then pan gesture stops pinch one but I need the opposite thing.
Updated
#interface SomeClass : UIViewController <UIGestureRecognizerDelegate>
...
#end
#implementation SomeClass
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
#end
You can create dependencies between recognizers using the requireGestureRecognizerToFail: method so that one gesture will only become eligible to begin when another has failed.
Depending on exactly what you need you may have to subclass and create your own gestures so that you can control how and when they begin and fail.
solved by editing pan gesture handler:
- (IBAction)panGRUsed:(id)sender {
UIPanGestureRecognizer *gr = (UIPanGestureRecognizer *)sender;
if (gr.numberOfTouches > 1) {
[gr setTranslation:CGPointZero inView:self.view];
} else {
...
}
}
I am making an iPad app where you can swipe/pan with 3 fingers at any time on the whole screen (cancel action)
It's working with a UISwipeGestureRecognizer or UIPanGestureRecognizer but the subviews underneath my fingers (for instance a UITableView or UIScrollview) received the touch and moves. Which I don't want.
My idea was to put a transparent UIView on top of the whole app that will forward touches to the other views or not. I tried something with hitTest but I think I didn't understand it well since the return number of touches isn't right and takes time...
Thanks a lot if you can help me with that :)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (event.type == UIEventTypeTouches) {
if (event.allTouches.count >= 2) {
return self;
}
}
return [super hitTest:point withEvent:event];
}
I think you must use the
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
delegate of UIGestureRecognizer to define which gestures is valid in the same time.
E.g:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
NSLog(#"gestRecogn: %# otherGestRec: %#",[[gestureRecognizer class] className],[[otherGestureRecognizer class] className]);
if ([[[gestureRecognizer class] className] isEqualToString:#"UIScrollViewPanGestureRecognizer"] && [[[otherGestureRecognizer class] className] isEqualToString:#"UILongPressGestureRecognizer"]) {
return FALSE;
}
if ([[[gestureRecognizer class] className] isEqualToString:#"UILongPressGestureRecognizer"] && [[[otherGestureRecognizer class] className] isEqualToString:#"UIScrollViewPanGestureRecognizer"]) {
return FALSE;
}
return TRUE;
}