UIGesture returns UIImageView and not custom view - ios

I have added a custom view to my rootview and added a UITapGesture. When calling on the 'sender.view' of the UITapGesture code it no longer is represented by my custom UIView, but instead 'sender.view' is of type UIImageView.
So it really makes it hard to send messages to my custom view when iOS is expecting a UIView - the warning I get is: "Incompatible pointer types sending UIView to parameter CardView (my custom view).
I think it has to do with chain of response; the documentation says - "When iOS recognizes an event, it passes the event to the initial object that seems most relevant for handling that event, such as the view where a touch occurred." - About Events in iOS
The keyword here is "seems" - how can I tell iOS that my custom View is the one that should handle the gesture?
Question: How can I get sender.view to refer directly to my custom view?
Here is some code below:
//Creates the Card's view
CardView *cardView = [[CardView alloc]initWithFrame:CGRectMake(0, 0, 67,99)];
//For Single Tap
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleSingleTapGesture:)];
[cardView addGestureRecognizer:tapGesture];
[self.view addSubview:cardView];

In the handleSingleTapGesture: will give u the (UITapGestureTecongnizer *)sender so cast like this:
CardView *card = (CardView *)sender.view;
//do you stuff with card

Related

Put gesture recognizers in view or controller class

I was looking for GestureRecognizer tutorials on the web and saw that most people used for example UIPanGestureRecognizer directly in the view. Is this common practice, if so, why not in the controller?
I generate my views in the controller and have methods that I would need to call, when the gesture is used. How should the delegation method look like, if my gesture recognizer is in the view class, and the method to be called in the controller class?
A simple UIGestureRecognizer implementation, and the most common one in my opinion is as follows:
//this is where you create the view that you want to add the gesture recognizer
UIImageView * imageView = [[UIImageView alloc] initWithFrame:frame];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] init];
tapRecognizer.numberOfTapsRequired = 1;
[tapRecognizer addTarget:self action:#selector(imageViewTapped:)];
imageView.userInteractionEnabled = YES;
[imageView addGestureRecognizer:tapRecognizer];
After creating the gesture recognizer and adding it to a UIView subclass you can get the taps with the function you pointed above:
- (void)imageViewTapped:(UIGestureRecognizer *)gestureRecognizer
{
if ( gestureRecognizer.state == UIGestureRecognizerStateRecognized )
{
NSLog(#"tap recognized!");
}
}
So basically, you dont need to worry about the controller/view dilemma.
You always add the gesturerecognizer to a view. and when adding the gesture recognizer you add a target function, which you need to implement in the controller class.
P.S This SO Question might clarify in detail of the dilemma you are facing
In one sense, yes, this violate the MVC pattern. As you say, the view shouldn't have anything to do with how to control it, it's a better habit to group such code in another part of the application.
You can drag an gesture into the storyboard(into the view controller),too.Then from the document outline you make an action(in the vc) for that gesture

Gesture recogniser in different class?

I was wondering if this was possible.
To have a class which adds new imageViews to the main view and assigns a gesture recogniser to it.
So in my view builder class, I have the following:
UIImageView *headerPlusIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"plusIcon.png"]];
headerPlusIcon.frame = CGRectMake(header.frame.size.width - 2.5*(logoSize - 8), yPosition*1.6, logoSize*0.9, logoSize*0.9);
headerPlusIcon.userInteractionEnabled = YES;
UIGestureRecognizer *headerTapGesture = [[UIGestureRecognizer alloc] initWithTarget:mainView action:#selector(testTapGesture:)];
[headerPlusIcon addGestureRecognizer:headerTapGesture];
The tap gesture method goes like this:
-(void)testTapGesture:(UITapGestureRecognizer *)gesture
{
dispatch_async(dispatch_get_main_queue(), ^{
mainView.backgroundColor = [UIColor redColor];
});
}
mainView is passed into this class via the constructor and is simply the main view.
This is called like this:
mainViewbuilder = [[MainViewBuilder alloc] initWithBaseView:self.view];
[mainViewbuilder buildHeader];
Unfortunately the tap gesture method never gets called... how would this be done properly?
Thanks!
Try UITapGestureRecognizer
Apple Docs on UITapGestureRecognizer
The code you posted never adds your headerPlusIcon to the view hierarchy. You say in your answer to Adam that you got it working, but I don't see how if you don't add the headerPlusIcon to your view controller's content view hierarchy somewhere.
Note that mucking around in a view controller's view hierarchy from outside is not good object-oriented design.
It would be better to have the view controller ask another object for a view (probably through a protocol) and then add that view itself.

is it possible to add a GestureRecognizer to a label in a custom UIView subview

I am refactoring a ViewController that I have adopted and is creating UIViews in the controller code. I'd like to move it to a custom UIView but would like to handle the Gesture Recognizer in the controller.
I have an ItemViewController which has a custom UIView. Within the ItemController, I'd like to do something like:
ItemView *itemView = [[ItemView alloc] initWithFrame:CGRectMake(30.0f,_runningYPosition,100.0f, 50.0f)];
UITapGestureRecognizer *tapRecognizer2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapRecognized:)];
itemView.miHeaderLabel.tag = [item itemID];
[itemView.miHeaderLabel addGestureRecognizer: tapRecognizer2];
that references
- (void)tapRecognized:(id)sender
{
...
}
in ItemViewController (NOT in the custom view).
But it doesn't seem to work. Is it possible to add a GestureRecognizer to a label that is a property of a subview in a ViewController? Anything obvious I'm doing wrong?
You need to set userInteractionEnabled to YES on the label for it to accept touches (and therefore for the gesture to receive touches).

Tap gesture recognizer on image throws error when passing event

I have a UIImageView inside of a custom cell. I am creating a custom tap gesture recognizer for when the UIImageView is tapped to load another detail view.
The tap gesture is set up like so:
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTapped:event:)];
tapRecognizer.cancelsTouchesInView = YES;
tapRecognizer.numberOfTapsRequired = 1;
tapRecognizer.delegate = (id)self;
[cell.userImage addGestureRecognizer:tapRecognizer];
cell.userImage.userInteractionEnabled = YES;
I am using imageTapped:event: so that I can detect what cell the user is tapping and load the data accordingly. The problem is I get this error:
If I get rid of event like so, its works perfectly with no issues.
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTapped:)];
I have used this method before in another application but for some reason I cannot get it to work properly with this error. Anyone recognize what this is? Thanks!
You need to read the documentation on UIGestureRecognizer...
A gesture recognizer has one or more target-action pairs associated
with it. If there are multiple target-action pairs, they are discrete,
and not cumulative. Recognition of a gesture results in the dispatch
of an action message to a target for each of those pairs. The action
methods invoked must conform to one of the following signatures:
- (void)handleGesture;
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;
Using one of these signatures will prevent the crash as you have already observed. You could then access the image view that was involved in the gesture by inspecting the recognizer's view property, and from this you will be able to access the appropriate UITableView cell.

Homemade tap gesture recognizer for iOS

I'd like to code my own tap gesture recognizer, to detect the number of taps and number of touches (I don't want to use the iOS tap gesture recognizer because I want to extend it later in various other manners) ;
I tried the following : use the first motionBegin number of touches as the numberOfTouches of the tap, increment the numberOfTaps, and start the tap detection timer to detect the tap gesture if no new taps has been seen in a while
The problem is that one quickly realises that when doing a double-touch tap gesture, iOS either correctly detects one motionBegin with a double touch, or two quick one touch events. I guess a correct implementation should try to detect those quick one touch events that happen closely, but I'm wondering if there is a better way to implement the gesture recognizer.
Someone knows how the iOS tap gesture is implemented?
1. Add UIGestureRecognizerDelegate in your .h file. like
#interface finalScreenViewController : UIViewController <UIGestureRecognizerDelegate>
{
// do your stuff
}
2. Create a view in your viewDidLoad method (or any other method) you wanna to add the gesture in your .m file
ex
UIView * myView=[[UIView alloc]init];
myView.frame=CGRectMake(0,0.self.view.frame.size.width,self.view.frame.size.height);
[self.view addSubView: myView];
UITapGestureRecognizer *letterTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapMethod:)];
letterTapRecognizer.numberOfTapsRequired = 1;
[myView addGestureRecognizer:letterTapRecognizer];
3. you can get view by
- (void) tapMethod:(UITapGestureRecognizer*)sender {
UIView *view = sender.view;
NSLog(#"%d", view.tag);//By tag, you can find out where you had tapped.
}

Resources