Get reference of gesture recognizer in xib not using IBOutlet - ios

I create a single tap and double tap gesture recognizer in a xib file, and I want to access it in a category, but the Referring Outlet of xib in property and it cannot be inserted in a category, can I use code to access gesture recognizer reference in function viewDidLoad?

Yes you can. A view keeps a list of its Gesture Recognizers so you just need to loop through them.
for (UIGestureRecognizer *recognizer in self.gestureRecognizers)
{
// You need a way to identify it here
}
In this case, if your category is extending a view controller, you just need to know which view contains the gesture recognizer you want.
#property(nonatomic, copy) NSArray<__kindof UIGestureRecognizer *> *gestureRecognizers;
https://developer.apple.com/documentation/uikit/uiview/1622542-gesturerecognizers?language=objc
Edit:
If your category is extending a ViewController change the loop to self.view.gestureRecognizers (or any other view that you attached it to)

Related

Can I drag imageView gestureRecongnizer to .m file as Action?

First of all, I have open the image's User Interaction Enabled.
But why I can't drag the gesture ?
The gestureRecognizers in Outlet Collections is a outlet to the gesture recognizers of that view, not an action of its gesture recognizers.
What you need to do is adding a gesture recognizer to the image view by dragging one from the Object Library and adding its action
You can drag the gesture like this:
Drag a TapGesture Recognizer to the ViewController in storyboard:
You should write a IBAction method in the ViewController.m:
```
-(IBAction)tapGesture:(id)sender {
}
```
Drag the TapGesture Recognizer to ViewController, then choose the delegate and the tapGesture: method:
Then you can drag the imageView's gestureRecognizers to the gesture:
The function you write in ViewController.m is what you want.

Single tap gesture to multiple View using storyboard

How to have single tap gesture to multiple Views using storyboard.
I drag 3 views and one tap gesture into UIView class.
Contacted three view to tap gesture and added action class handleGesture Method on tap on any one the tree view it should trigger the method action.
using story board.
But i want to do it with single tap gesture is it possible or not.
try with this, define a variable UITapGestureRecognizer with your method, after that, in a method or wherever you want, you can add this gesture to your multiple views
var recognizerMovements: UITapGestureRecognizer {
get { UITapGestureRecognizer(target: self, action: #selector(self.myActionMethod)) }
}
self.myFirstView.addGestureRecognizer(myActionMethod)
self.mySecondView.addGestureRecognizer(myActionMethod)

iOS: How to write handler for Tap Gesture Recognizer if dragged in from storyboard?

I have an image and in the storyboard I've dragged a Tap Gesture Recognizer on top of this image and changed the settings:
For my TGR:
For my image:
How do I hook this up to my controller now? I want a method to fire off when the double tap happens. Is there some sort of protocol I have to conform to? Do people normally do this from the storyboard or programmatically in viewDidLoad? I don't mind doing it another way if that's the general trend of things.
connect the gesture recognizer as a outlet to your ViewController and in your viewDidLoad :
[self.yourGesture addTarget:self action:#selector(didTapOnImage:)] ;
and then declare your method didTapOnImage method :
-(void)didTapOnImage:(UIGestureRecognizer*) recognizer
{
//do your work here
}

UITapGestureRecognizer on UIView and Its Subview Respond Together When Subview Is Tapped

UITapGestureRecognizer is applied to both UIImageView and its subview (UITextView). However, when I tap on subview, the receiver becomes subview and its parent view (i.e. UIImageView + UITextView). It should however be only subview because that was the one I tapped. I was assuming nested gestures would react first but apparently parent receives the fist tap and then it goes to child.
So, there are different solutions out there for various scenarios (not similar to mine but rather buttons inside scroll view conflict). How can I easily fix my issue without possible subclassing and for iOS 6+ support? I tried delaying touch on start for UIGestureRecognizer on UIImageView and I tried setting cancelsTouchesInView to NO - all with no luck.
Try the following code:
conform the <UIGestureRecognizerDelegate> to your class.
set yourGesture.delegate = self;
then add this delegate Method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// return YES (the default) to allow the gesture recognizer to examine the touch object, NO to prevent the gesture recognizer from seeing this touch object.
if([touch.view isKindOfClass: [UITextView class]] == YES)] {
return YES;
}
else {
return NO;
}
}
Hope it will solve your issue. Enjoy Coding..!!!!
That's exactly what is it supposed to do.
View hierarchy is like a tree structure and its traversal during a touch gesture starts from the root node. It is very likely for your parent view to receive gesture first and then its subviews. The traversal skips the nodes for which
userInteractionEnabled = NO.
since, you don't have any code I can't help you to play with this flag. A more general solution is to always set gesture only for your parentView and in the gesture delegates check the coordinates if it belongs to any one of the subview and if yes then call your gesture method for your subview.
Not a clean approach but works. !!
you should implement the UIGestureRecognizer delegate methods and apply the correct policy to the gesture, when multiple gesture are recognized

Detect touch event on UIScrollView AND on UIView's components [which is placed inside UIScrollView]

I have UIViewController on my simple storyboard IPad project which contains UIScrollView which is placed over entire surface (1024 x 768). I have created 3 XIB files which are UIViews which my application loads on start in viewDidLoad and add them into UIScrollView. Each of these 3 XIB files contains only one UIButton.
This is hierarchy:
~ UIViewController (UIViewControllerClass is class for this
UIViewController)
~~ UIScrollView (contains 3 identical UIViews)
~~~ UIView (UIViewClass is File's Owner for this XIB file)
~~~~ UIButton
I would like that my UIViewControllerClass becomes aware of both: touch anywhere on UIScrollView component AND if UIScrollView is touched, if UIButton inside of UIView in UIScrollView is touched, to have information that exactly that button is touched.
I made IBAction inside UIViewClass for touch on UIButton inside UIView in UIScrollView and when I set User Interaction Enabled = YES on all elements (UIViewController, UIView and UIScrollView) this method is called as it should.
But at this point my UIViewControllerClass isn't aware that touch occurred inside UIScrollView on that UIButton. I made touch recognizer like this:
UITapGestureRecognizer *touch = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTouch)];
touch.numberOfTouchesRequired = 1;
and added it to UIScrollView component. In this way I am able to detect touch event on UIScrollView component in UIViewControllerClass, but touch event handler for UIButton in UIView which is inside UIScrollView isn't called anymore.
So, I need to have these two informations in UIViewControllerClass:
Touch on UIScrollView component was made
Touch on UIButton in UIView which is inside UIScrollView (if this button was touched) was made
I suppose that attaching touch event recognizer to entire UIScrollView component isn't solution, since it disables all touch event handlers I wrote inside UIViewClass.
I think solution is that somehow touches which are made on components in UIView inside UIScrollView should be sent up to UIViewControllerClass, but I didn't found a way to do this.
If anyone can help me, I'd be very grateful. Thanks in advance.
[edit #1: ANSWER by Zheng]
Tap gesture must have cancelsTouchesInView option set to NO!
For my case above, this line solves everything:
touch.cancelsTouchesInView = NO;
Many thanks to Zheng.
I don't know if this works for you or not, but I've given an answer about touch events for views inside scrollview here:
Dismissing the keyboard in a UIScrollView
The idea is to tell the scrollView not to swallow up all tap gestures within the scroll view area.
I'll paste the code here anyways, hopefully it fixes your problem:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
// prevents the scroll view from swallowing up the touch event of child buttons
tapGesture.cancelsTouchesInView = NO;
[pageScrollView addGestureRecognizer:tapGesture];
[tapGesture release];
...
// method to hide keyboard when user taps on a scrollview
-(void)hideKeyboard
{
[myTextFieldInScrollView resignFirstResponder];
}
You can subclass your UIScrollView and override the method - hitTest:withEvent: which is called by the system to determine which view will handle the event. Whenever it is called, you can assume that a touch event occurred inside the scroll view, and by calling the super implementation, you can get the view which would normally process the event.
you can capture any kind of gestures in the UIscrollView. Make sure you also handle some of the default properties as well like set cancelsTouchesInView property to false, it is true by default. Also give some tag nos to your sub views to distinguish in selectors. & also enable their User interaction to true.
let tap = UITapGestureRecognizer(target: self, action:
selector(didTapByUser(_:)))

Resources