I'm having a UITextView, in which I can't see the long press text magnifier. Is there a way to force that magnifier to appear?
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
BOOL isAtLeastOneGestureInlineTextView = [self isInlineTextView:gestureRecognizer.view] || [self isInlineTextView:otherGestureRecognizer.view];
if ((gestureRecognizer == [self longPressGesture]) && !isAtLeastOneGestureInlineTextView) {
return NO;
}
if (gestureRecognizer == [self panGesture]) {
return NO;
}
return YES;
}
- (BOOL)isInlineTextView:(UIView *)view {
return [view isKindOfClass:[SFGInlineTextView class]];
}
Apparently there was this check which disabled long press. To preserve former implementation, I've checked the gestures to not be the desired textView.
Related
I have a UIScrollView with the same frame as the containing view controller.
When the zoom scale of the scrollview is greater than 1, swiping left to right starting from the left 50% of the screen causes the interactivePopGestureRecognizer to activate and dismiss the view controller.
This only happens when the device is in landscape. It works fine when in portrait.
Is there any special handling needed to make this gesture work normally with a scrollview?
1、set interactivePopGestureRecognizer delegate to self (Custom UINavigationController)
self.interactivePopGestureRecognizer.delegate = self;
2、enable simultaneously recognize UIScrollView UIGestureRecognizer
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (self.interactivePopGestureRecognizer == gestureRecognizer) {
if ([otherGestureRecognizer.view isKindOfClass:UIScrollView.class]) {
UIScrollView *scrollView = (UIScrollView *)otherGestureRecognizer.view;
if ((scrollView.contentSize.width > CGRectGetWidth(self.view.bounds) && scrollView.contentOffset.x == 0)) {
return YES;
}
}
}
return NO;
}
The 1 step:
#implementation UIScrollView (AllowPanGestureEventPass)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]
&& [otherGestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]])
{
return YES;
}
else
{
return NO;
}
}
The 2 step:
[_scrollView.panGestureRecognizer requireGestureRecognizerToFail:screenEdgePanGestureRecognizer];
We currently are using a solution similar to the one mentioned here (see Ares's answer). This does not seem to work in iOS8.
I have a form sheet, and I want to dismiss it as soon as the user taps on the dimmed view 'behind' the form sheet.
Previously, this seemed possible by adding a gesture recogniser to the window, and checking tap-location to see if it was outside the current form sheet;
I also noticed the point needs to be converted (switch x and y) of the device is used in landscape mode. Other than that, right now it only receives gestures that occurred from inside the form sheet, where before any tap gesture anywhere on the screen would trigger an event.
- (void)viewDidLoad
{
[super viewDidLoad];
self.recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapBehind:)];
self.recognizer.numberOfTapsRequired = 1;
self.recognizer.cancelsTouchesInView = NO;
[self.view.window addGestureRecognizer:self.recognizer];
}
- (void)handleTapBehind:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded)
{
CGPoint location = [sender locationInView:nil];
if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) && IOS8)
{
location = CGPointMake(location.y, location.x);
}
// if tap outside pincode inputscreen
BOOL inView = [self.view pointInside:[self.view convertPoint:location fromView:self.view.window] withEvent:nil];
if (!inView)
{
[self.view.window removeGestureRecognizer:sender];
[self dismissViewControllerAnimated:YES completion:nil];
}
}
}
As mentioned in the thread you referenced, you should add a UIGestureRecognizerDelegate and implement the methods:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return YES;
}
I have several pages on UIPageViewController. Each page is created from its own view, that has nested views. One of them is image. I want to have contol made in the way, that user can change pages by swipe on everything but image. Swipe on image will change images and not the page.
How can I achieve this? I have added UISwipeGestureRecognizer to the image, set userInteraction to YES, but swipe is send through and cause page turn.
I have this code in view load method (awakeFromNib)
UISwipeGestureRecognizer *swipeGestureRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(changeImageRight)];
[swipeGestureRight setDirection:UISwipeGestureRecognizerDirectionRight];
swipeGestureRight.delegate = self;
swipeGestureRight.numberOfTouchesRequired = 1;
[self.image addGestureRecognizer:swipeGestureRight];
Something like this should do the trick for you :
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
if (gestureRecognizer == self){
if ([otherGestureRecognizer isMemberOfClass:self.class]){
if ([self isGestureRecognizerInSuperviewHierarchy:otherGestureRecognizer]){
return YES;
} else if ([self isGestureRecognizerInSiblings:otherGestureRecognizer]){
return YES;
}
}
}
return NO;
}
- (BOOL) isGestureRecognizerInSiblings:(UIGestureRecognizer *)recognizer{
UIView *superview = self.view.superview;
NSUInteger index = [superview.subviews indexOfObject:self.view];
if (index != NSNotFound){
for (int i = 0; i < index; i++){
UIView *sibling = superview.subviews[i];
for (UIGestureRecognizer *viewRecognizer in sibling.gestureRecognizers){
if (recognizer == viewRecognizer){
return YES;
}
}
}
}
return NO;
}
- (BOOL) isGestureRecognizerInSuperviewHierarchy:(UIGestureRecognizer *)recognizer{
if (!recognizer) return NO;
if (!self.view) return NO;
//Check siblings
UIView *superview = self.view;
while (YES) {
superview = superview.superview;
if (!superview) return NO;
for (UIGestureRecognizer *viewRecognizer in superview.gestureRecognizers){
if (recognizer == viewRecognizer){
return YES;
}
}
}
}
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
if ([gestureRecognizer respondsToSelector:#selector(gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:)]){
return [(id <UIGestureRecognizerDelegate>)gestureRecognizer gestureRecognizer:gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:otherGestureRecognizer];
}
return NO;
}
I have a gesture recognizer on my view controller which I use to slide in/out the navigation bar. Unfortunately there is a bad NSZombie that makes the whole app crash when I go swipe to go to the previous controller. It's very difficult to track because it only happens in a specific view controller.
Here is the error:
[MyViewController gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:]: message sent to deallocated instance
And here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UIPanGestureRecognizer *pgr = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pgr:)];
pgr.delegate = self;
[self.view addGestureRecognizer:pgr];
}
- (void)pgr:(UIPanGestureRecognizer *)gesture {
// Check if this is the first touch
if (gesture.state == UIGestureRecognizerStateBegan) {
CGPoint point = [gesture locationInView:gesture.view];
self.start = point.y;
}
CGPoint point = [gesture locationInView:gesture.view];
self.currentX = point.x;
self.offsetY = point.y - self.start;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]]) {
return YES;
}
return NO;
}
The delegate method is
- (BOOL)shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
Try to use
- (BOOL)shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if ([otherGestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]]) {
return YES;
}
return NO;
}
I have a UITableView with a gesture recognizer added:
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
[myTableView addGestureRecognizer:gestureRecognizer];
gestureRecognizer.cancelsTouchesInView = NO;
... everything works fine when tapping on the tableview to dismiss the keyboard. My problem is, my hideKeyboard method also calls when tapping on the "clear" button on my UITextField. Very strange.
commentTextField = [[UITextField alloc] initWithFrame:CGRectMake(5, 5, 310, 35)];
commentTextField.contentVerticalAlignment =UIControlContentVerticalAlignmentCenter;
commentTextField.borderStyle = UITextBorderStyleRoundedRect;
commentTextField.textColor = [UIColor blackColor]; //text color
commentTextField.font = [UIFont fontWithName:#"Helvetica" size:14.0]; //font size
commentTextField.placeholder = #"Enter a comment..."; //place holder
commentTextField.autocorrectionType = UITextAutocorrectionTypeNo; // no auto correction support
commentTextField.keyboardType = UIKeyboardTypeDefault; // type of the keyboard
commentTextField.returnKeyType = UIReturnKeySend; // type of the return key
commentTextField.clearButtonMode = UITextFieldViewModeAlways; // has a clear 'x' button to the right
commentTextField.delegate = self;
[commentTextField setHidden:NO];
[commentTextField setEnabled:YES];
[commentTextField setDelegate: self];
hide keyboard method:
- (void) hideKeyboard{
if(keyboard){
[commentTextField resignFirstResponder];
[UIView animateWithDuration:.3
delay:.0
options:UIViewAnimationCurveEaseInOut
animations:^{ // start animation block
[myTableView setFrame:CGRectMake(0, myTableView.frame.origin.y + 216, myTableView.frame.size.width, myTableView.frame.size.height)];
}
completion:^(BOOL finished){
}];
keyboard = 0;
}
}
Any help would be appreciated, thanks!
The following is a little more general - it's not coupled to your specific views:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UITextField class]] ||
[touch.view isKindOfClass:[UIButton class]])
{
return NO;
}
return YES;
}
Also, don't forget to set the delegate for the gesture recognizer, and mark the class as implementing the UIGestureRecognizerDelegate protocol.
I had the same issue. I also implemented the following method in my view:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ((touch.view == self.textField) && (gestureRecognizer == self.tapGestureRecognizer))
{
return NO;
}
return YES;
}
But it still didn't work. So I set a break in the method and saw that when I click the field, touch.view would be set to it but when I clicked on the clear button it was coming in as a UIButton*. At that point it was obvious what was happening and what to do to fix it. The below resolves the issue.
if((touch.view == self.textField || [self.textField.subviews containsObject:touch.view]) && (gestureRecognizer == self.tapGestureRecognizer))
{
return NO;
}
My issue with Ezmodius' approach is that he depends on a property called 'textField' and my UIViewController is a controller from which all my other UIViewControllers inherit, so i needed to implement a more generic approach: whenever there was a textfield in any UIViewController that needed to be cleared, i implemented the following (inside the same gestureRecognizer method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UITextField class]] ||
([touch.view isKindOfClass:[UIButton class]] && [touch.view.superview isKindOfClass:[UITextField class]]))
{
return NO;
}
return YES;
}
So basically im checking whether it is a textfield or a button whose superview is a textfield (in this case, the clear button inside the textfield) and it works like a charm for me. I implemented this in my base UIViewController class and it works for every page where this happens.