Button actions and tap gestures are not working on UIView XIB - ios

I added custom UIView with XIB. I just tried to perform button actions and tapgestures , nothing is working eventhough user interaction enabled for all elements including ContentView.
Intializing UIView
-(void)initializeSubviews {
self.backgroundColor = [UIColor clearColor];
[[[NSBundle mainBundle]loadNibNamed:#"DatesView" owner:self options:nil]firstObject];
[self addSubview:self.contentView];
// self.contentView.frame = self.bounds;
[self.fromDateButton addTarget:self action:#selector(tapOnfromDate:) forControlEvents:UIControlEventTouchUpInside];
self.fromDateButton.backgroundColor = [UIColor redColor];
}
Tap gestures
UITapGestureRecognizer *fromDateTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnfromDate)];
[datesView.contentView addGestureRecognizer:fromDateTapRecognizer];
[datesView.fromMonthYearLabel addGestureRecognizer:fromDateTapRecognizer];
[datesView.fromDayLabel addGestureRecognizer:fromDateTapRecognizer];
Button Action
[datesView.fromDateButton addTarget:self action:#selector(tapOnfromDate) forControlEvents:UIControlEventTouchUpInside];
UIView interface

Couple things...
1) By commenting out this line in your view subclass:
// self.contentView.frame = self.bounds;
the view ends up with a frame of 0,0. The button and labels etc are visible because the view defaults to .clipsToBounds = NO, but the objects do not receive user interaction.
2) A UITapGestureRecognizer is a single instance. If you add it to one view, then try to add it to additional views, it will only exist on the last view to which is was added.
Try it like this (be sure to un-comment the above line):
- (void)viewDidLoad {
[super viewDidLoad];
// do all the loading stuff here...
// local declaration
UITapGestureRecognizer *tapRecognizer;
// Optional --- make *sure* user interaction is enabled
[datesView.contentView setUserInteractionEnabled:YES];
[datesView.fromMonthYearLabel setUserInteractionEnabled:YES];
[datesView.fromDayLabel setUserInteractionEnabled:YES];
// new recognizer
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnfromDate:)];
// add it to contentView
[datesView.contentView addGestureRecognizer:tapRecognizer];
// new recognizer
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnfromDate:)];
// add it to fromMonthYearLabel
[datesView.fromMonthYearLabel addGestureRecognizer:tapRecognizer];
// new recognizer
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnfromDate:)];
// add it to fromDayLabel
[datesView.fromDayLabel addGestureRecognizer:tapRecognizer];
// add target action to fromDateButton
[datesView.fromDateButton addTarget:self action:#selector(fromDateButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
}
- (void) tapOnfromDate: (UITapGestureRecognizer *)recognizer {
NSLog(#"Tapped! %#", recognizer.view);
}
- (void) fromDateButtonTapped: (id)sender {
NSLog(#"Button Tapped! %#", sender);
}

Related

UITapGesture Selector for UILabel issue

I added tapGesture for self.view and UILabel (subview of mainView), each performs different selectors.
But the only main view tapGesture is being called and label tapgesture is not being called. How it is handled?
Here is the code:
UITapGestureRecognizer *tapGesForSelf = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesForSelf:)];
[self.view addGestureRecognizer:tapGesForSelf];
UITapGestureRecognizer *tapLblClick = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesForLbl:)];
[lbl addGestureRecognizer:tapLblClick];
For two selectors only one method is called tapGesForSelf.
Here lbl is the subview of self.view.
Try this
- (void)viewDidLoad {
[super viewDidLoad];
[_lbl setUserInteractionEnabled:YES];
UITapGestureRecognizer *tapGesForSelf = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesForSelf:)];
[self.view addGestureRecognizer:tapGesForSelf];
UITapGestureRecognizer *tapLblClick = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesForLbl:)];
[_lbl addGestureRecognizer:tapLblClick];
[tapGesForSelf requireGestureRecognizerToFail:tapLblClick];
}
- (void)tapGesForSelf:(UITapGestureRecognizer *)gesture
{
NSLog(#"self");
}
- (void)tapGesForLbl:(UITapGestureRecognizer *)gesture
{
NSLog(#"label");
}
I post answer for your question now once I tried and it worked well.
First see the label in design.I set label text as "Tap Me"
Now I set the code for view and label
- (void)viewDidLoad
{
[super viewDidLoad];
//TapGesture for Label
UITapGestureRecognizer *tapLabel = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(actionTapLabel:)];
tapLabel.delegate = self;
tapLabel.numberOfTapsRequired = 1;
lblTapMe.userInteractionEnabled = YES;
[lblTapMe addGestureRecognizer:tapLabel];
//TapGesture for View
UITapGestureRecognizer *tapMainView = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(actionTapMainView:)];
tapMainView.delegate = self;
tapMainView.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapMainView];
}
//Action method for Label
-(void)actionTapLabel:(UITapGestureRecognizer *)gestureOnLabel{
UILabel *label = (UILabel *)gestureOnLabel.view;
NSLog(#"Lable text is - %#",label.text);
}
//Action method for View
-(void)actionTapMainView:(UITapGestureRecognizer *)gestureOnMainView{
NSLog(#"The Main view is tapped");
}
Output Screenshot
Please setUserInteractionEnabled:YES for interact the TapGesture
[lbl setUserInteractionEnabled:YES];

Onclick Event UIView, while using multiple UIViews

I am new in IOS Dev, was searching onclick event for UIView and i found this code that worked perfectly. But it doesnt call specific UIView as i am using multiple UIViews and want to add event on all of them separately while this code calls handleSingleTap onclick of either UIView. plz help..
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];
}
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
NSLog(#"Clicked");
}
You can create UITapGestureRecognizer and add it to the views you want it to be clicked.
You can also set up tag property on each view to find out which view was clicked.
For example:
UITapGestureRecognizer *singleFingerTap1 =
[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
view1.tag = 1;
[view1 addGestureRecognizer:singleFingerTap1];
UITapGestureRecognizer *singleFingerTap2 =
[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
view2.tag = 2;
[view2 addGestureRecognizer:singleFingerTap2];
//..and so on
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
UIView *viewClicked = recognizer.view;
NSLog(#"Clicked: %d", viewClicked.tag);
}
The other solution is add one gesture recogniser to the main view (the view which hold the others view, something as you posted) and in handleSingleTap: method check if the point is inside the view:
BOOL isPointInsideView1 = [view1 pointInside:location withEvent:nil];
BOOL isPointInsideView2 = [view1 pointInside:location withEvent:nil];
But ic can failed when one view override another.

Not getting button action/ Single tap on custom MKannotation call out view

I have created a custom annotation and a call out for my map view. I need to navigate to another view when the user clicks on call out view or he clicks to the button that added as sub view to the callout view. But both gesture recognizer and add target is not working for me in this case. The setSelected: method was invoked and the view get hidden when tap occurs in call out view.
#interface VBPunchCardAnnotation : MKAnnotationView{
UIView *calloutView;
}
- (id)initWithAnnotation:(id )annotation reuseIdentifier:(NSString *)reuseIdentifier deal:(id)punchdeal
{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
calloutView = [[UIView alloc] init];
calloutView.hidden = YES;
infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
[calloutView addSubview:infoButton];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(annotationTapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.delegate = self;
[calloutView addGestureRecognizer:singleTap];
[infoButton addTarget:self action:#selector(annotationTapped:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:calloutView];
return self;
}
-(void)setSelected:(BOOL)selected animated:(BOOL)animated
{
// show/hide callout and swap pin image
calloutView.hidden = !selected;
self.image = !selected ? normalPin : selectedPin;
// dispatch an event to alert app a pin has been selected
if(selected) [[NSNotificationCenter defaultCenter] postNotificationName:#"punchCardAnnotation" object:self];
}
-(void)annotationTapped:(id)sender{
[self.delegate punchCardAnnotationClickedForDeal:self.punchDeal];
}
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
UIView* hitView = [super hitTest:point withEvent:event];
if ([hitView isKindOfClass:[UIButton class]]) {
}
}
Finally I got the answer. It;s here
Followed this tutorial. Really great solution.
https://github.com/nfarina/calloutview
Happy coding!!

iOS touching a UIImageView

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
container = [[UIView alloc] initWithFrame:self.view.frame];
UIImageView* main_im0 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"icon1.png"]];
[container addSubview:main_im0];
[self.view addSubview:container];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *tt = [touches anyObject];
UIImageView *touchedview=(UIImageView*)[tt view];
NSArray *views = [container subviews];
for (UIImageView* im in views)
{
UIImageView* focus=im;
if (touchedview==focus)
{
}
}
}
I have this piece of code that setting up an ImageView called main_im0 which is put into a UIView container which then put into view. When I clciked on the main_im0, I expect the touch function would hit the condition of touchedview==focus. However, I couldn't get that condition activated? what's wrong?
Please enable
main_im0.userInteractionEnabled = YES;
by default it's No for UIImageView
Jason, maybe I am misinterpreting your code but aren't you going a round about way of achieving a tap gesture on a UIView?
You can use:
// enable user interaction with this view
main_img0.userInteractionEnabled = YES;
// setup a tap gesture to call a method once triggered (like a javascript mouseClick event)
UITapGesture *tapGesture = [[UITapGesture alloc] initWithTarget:self selector:#selector(myMethodToDoSomething)];
[main_img0 addGestureRecognizer:tapGesture];
// if you are not using Automatic Reference Counting, then remember to release your allocated tapGesture object
[tapGesture release];
...somewhere later in your code....
// method to do something
-(void)myMethodToDoSomething
{
NSLog(#"This method executed");
}
Now when you tap on your main_img0 view, the method "myMethodToDoSomething" will execute
By the way, if you just want a custom looking button with your own photoshop designed image, you can simply create a UIButton with code and set the background image property of the UIButton. Like so:
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[button setImage:[UIImage imageNamed:#"mybutton.png"] forControlState:UIControlStateNormal];

UIGestureRecognizer in UIView Object

I have created a UIViewController, which contains a UIView object.
I want the UIView object response to a single tap by 1 finger, and also pinch by 2 fingers.
I have clicked the "User Interaction Enabled" and the "Multiple touch" options in the xib.
I create both UITapGestureRecognizer, and UIPinchGestureRecognizer inside the UIView function initWithFrame:, as it is the only entry point for the UIView object. But the object doesn't response to the UIGestureRecognizer objects. Why? Or, where is the best place to put the UIGestureRecognizer objects?
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
// single tap
UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self addGestureRecognizer: singleTap];
// 2 fingers pinch
UIPinchGestureRecognizer* doubleMove = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleMove:)];
[self addGestureRecognizer: doubleMove];
}
return self;
}
Your problem is that when you instantiate your custom view subclass in IB, initWithCoder: is called. If you had done it programmatically using initWithFrame: it would have worked properly.
Two ways you can fix this,
Move the gestures setup to a different method and call them in both initWithFrame: and initWithCoder:. I would recommend doing this if you intend to reuse this component and expose some kind of callbacks on gestures.
If you want to implement this once and have a lot of interacting with the controller element, add them in viewDidLoad.
I tried your code and it works for me.
Where are you setting the view? Maybe it has any other view in front, or its superview has userInteractionEnabled disabled.
I created a UIView subclass and added this code:
-(void) handleSingleTap:(UITapGestureRecognizer *)gr {
NSLog(#"handleSingleTap");
}
-(void) handleDoubleMove:(UIPinchGestureRecognizer *)gr {
NSLog(#"handleDoubleMove");
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
// single tap
UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self addGestureRecognizer: singleTap];
// 2 fingers pinch
UIPinchGestureRecognizer* doubleMove = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleMove:)];
[self addGestureRecognizer: doubleMove];
}
return self;
}
Then, in my controller:
-(void) viewDidLoad {
[super viewDidLoad];
MyView * myView = [[MyView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
myView.backgroundColor = [UIColor greenColor];
[self.view addSubview:myView];
[myView release];
}
And it works.
i think if you are working with .xib, initialization can also be done in
-(void)awakeFormNib;
Adding the GestureRecognizers is typically done in the viewDidLoad method of the UIViewController.

Resources