Gesture for specific element in custom table view cell - ios

I'm using a custom table where every cell holds several elements, one of them is a favourite "star" icon.
I want to add a tap gesture so when the star icon is tapped it would change to "unfavourite" icon (and vice versa).
I've tried to add a tap gesture in cellForRowAtIndexPath with:
UITapGestureRecognizer *tapRecognizer;
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(favTapped)];
[[cell.contentView viewWithTag:1] addGestureRecognizer:tapRecognizer];
But tapping the icon would just call didSelectRowAtIndexPath (obviously).
My selector "favTapped" won't be called.
Any idea how to do it?
Thanks!

you need to add the
GestureRecognizer as property to your custom cell class.
in your customCell.h:
' #property (weak, nonatomic ) UIButton *yourButton; // or swipeGesture'
in tableView:cellForRowAtIndexPatch:
[cell.yourButton addTarget:self action:#selector(yourMethod) forControlEvents:yourControlEvent]; // also aviable for gestures
also verify if User interaction is enabled (in your interface builder, you can also override this in your own class or). the most simple way to do this is to write in tableView:cellForRowAtIndexPatch:
[cell.contentView setUserInteractionEnabled:YES];

Related

How do I make a UILabel *not* pass touches to the UITableViewCell it's embedded in?

I have a UITableView with a bunch of cells, and I add a UILabel to each. I want the UILabel, when tapped, to accept the touches, not the cell. Obviously if they tap outside of the label and still on the cell that is fine, but if it's on the label the cell should not cause a segue or action or whatever, only the label's action on tap should fire.
My normal method to cause this is to set the UIView's userInteractionEnabled to YES, but in this case when I set it on the label it doesn't cause anything different to happen. When I watch touchesBegan in the label subclass those methods do fire, but the cell selection does as well.
How do I make the UILabel not pass the touches on to the cell?
I recommend adding a UITapGestureRecognizer to the label and setting cancelsTouchesInView property to YES to prevent the touches from being delivered to the view upon gesture recognition, ex:
UITapGestureRecognizer *labelTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:nil];
labelTapGesture.cancelsTouchesInView = YES;
[label addGestureRecognizer:labelTapGesture];
label.userInteractionEnabled = YES;
And since you don't want the gesture to perform an action, you can set its action to nil.

Removing UIImageView if the user taps on any point outside the UIImageView

My app shows an UIView which contains four UIButtons, one of them removes the UIView, but I also need is to remove the UIView, including all containing buttons when the user taps outside it.
This is how I remove the UIView using a button action:
-(IBAction)closeSideTasks: (id)sender
{
UIView * backgroundView = (UIView *)[self.view viewWithTag:7];
[backgroundView removeFromSuperview];
}
Any help or advice is welcome.
MORE INFORMATION:
This is the scenario: there is a table view. If the user swipes from left to right on a row, then the UIView appears on the right side of the view. The UIView *newView is removed after tapping on each of the buttons inside it and executing each button action. But may be the user does not tap on any of the buttons, and the UIView remains on the view. Then, what I want to achieve is a way that the UIView *newView gets removed if the user taps anywhere outside it, to prevent that it remains always on the view...
Check out UITapGestureRecognizer.
Example:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] init];
tapGesture.delegate = self;
tapGesture.numberOfTapsRequired = 1;
tapGesture.numberOfTouchesRequired = 1;
[tapGesture addTarget:self action:#selector(tapChangeImage)];
[self.profileImageView addGestureRecognizer:tapGesture];
Now add the action method:
#pragma tap gestures
-(void)tapChangeImage{
// Remove view from superview!
}
Put a large button, full screen, with no graphics, no text, and a clear background. Have its action also remove the background

UICollectionViewCell subview receive tap insted

I have a UICollectionViewCell with some my content on it as image, labels, views.
I would like to obtain this behavior (like an opposite behavior of a normal cell):
this cell by default have a view (a simple UIView with an alpha set to show some opacity) like when it is not selected.
when a user select the cell this alpha view have to be removed.
If I try to install a UITapRecognizer:
// Create gesture recognizer
UITapGestureRecognizer *oneTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onShadowLayerPressed)];
// Set required taps and number of touches
[oneTap setNumberOfTapsRequired:1];
[oneTap setNumberOfTouchesRequired:1];
// Add the gesture to the view
[self.shadowView addGestureRecognizer:oneTap];
and after the method
- (void)onShadowLayerPressed
{
[super setSelected:YES];
[self setSelected:YES];
}
The tap is received from the self.shadowView but it doesn't send to the cell....
How can I solve this issue?
Thanks
You are using #property (nonatomic, getter=isSelected) BOOL selected and according to the docs,
You typically do not set the value of this property directly. Changing the value of this property programmatically does not change the appearance of the cell. The preferred way to select the cell and highlight it is to use the selection methods of the collection view object.
So you are supposed to use:
- (void)selectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition
Which is documented here.

how to get UILabel action in UITableView?

I have 3 UILabels in each cell of a table. I have added tap gesture recognisers to each one, but when it is tapped, how can I get the index path of the row that was tapped?
Here is my code
UILabel *tit_lbl=[[UILabel alloc]initWithFrame:CGRectMake(10,10,280,45)];
[tit_lbl setText:[[final_dictionaires_array objectAtIndex:indexPath.row] objectForKey:title]];
[tit_lbl setUserInteractionEnabled:YES];
[tit_lbl setTag:indexPath.row];
[btn addSubview:tit_lbl];
[tit_lbl release];
UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(goToArticleDetailsView:)];
[tit_lbl addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
With this, I can get the label action but I want to get which label is clicked in which Row ?? (I have 3 labels in each row).
I agree with the suggestions for using a button with a custom style instead of basically recreating buttons using labels and gesture recognisers. However, you'd still have the same problem. Which label was tapped? And which row of the table was it in?
You can find out which label was tapped by assigning tags to each one and then querying the view property of the gesture recogniser. The gesture recogniser will be the argument in your goToArticleDetailsView method:
-(void)goToArticleDetailsView:(id)sender
{
UITapGestureRecognizer *tapGR = (UITapGestureRecognizer*)sender;
if (tapGR.view.tag == 1)
// tapGR.view is the label that the gesture recognize was attached to
You can find out which row of the table was tapped using the gesture recogniser's locationOfTouch method, together with UITableView's indexPathForRowAtPoint: method:
CGPoint touchLocation = [tapGR locationOfTouch:0 inView:self.tableView];
NSIndexPath *tappedRow = [self.tableView indexPathForRowAtPoint:touchLocation];
A UILabel can not be clicked. You should use the UITextfield if you want to let the user to interact with the values.
To get the action you should sent a message to the instance of UITextField.
To get the right cell you can use the "indexPath"
good luck

How can I detect the touch event of an UIImageView?

I have placed an image (UIImageView) on the navigation bar. Now I want to detect the touch event and want to handle the event. How can I do that?
In practical terms, don't do that.
Instead add a button with Custom style (no button graphics unless you specify images) over the UIImageView. Then attach whatever methods you want called to that.
You can use that technique for many cases where you really want some area of the screen to act as a button instead of messing with the Touch stuff.
A UIImageView is derived from a UIView which is derived from UIResponder so it's ready to handle touch events. You'll want to provide the touchesBegan, touchesMoved, and touchesEnded methods and they'll get called if the user taps the image. If all you want is a tap event, it's easier to just use a custom button with the image set as the button image. But if you want finer-grain control over taps, moves, etc. this is the way to go.
You'll also want to look at a few more things:
Override canBecomeFirstResponder and return YES to indicate that the view can become the focus of touch events (the default is NO).
Set the userInteractionEnabled property to YES. The default for UIViews is YES, but for UIImageViews is NO so you have to explicitly turn it on.
If you want to respond to multi-touch events (i.e. pinch, zoom, etc) you'll want to set multipleTouchEnabled to YES.
To add a touch event to a UIImageView, use the following in your .m file:
UITapGestureRecognizer *newTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(myTapMethod)];
[myImageView setUserInteractionEnabled:YES];
[myImageView addGestureRecognizer:newTap];
-(void)myTapMethod{
// Treat image tap
}
You can also add a UIGestureRecognizer. It does not require you to add an additional element in your view hierarchy, but still provides you will all the nicely written code for handling touch events with a fairly simple interface:
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc]
initWithTarget:self action:#selector(handleSwipe:)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[imgView_ addGestureRecognizer:swipeRight];
[swipeRight release];
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc]
initWithTarget:self action:#selector(handleSwipe:)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[imgView_ addGestureRecognizer:swipeLeft];
[swipeLeft release];
I've been on different threads on the past few hours trying to find a solution for my problem, to no avail. I see that many developers share this problem, and I think people here know about this. I have multiple images inside a UIScrollView, trying to get tap events on them.
I am not getting any events from an UIImangeView, but I do get an event from a similar UILable with very similar parameters I am setting to it. Under iOS 5.1.
I have already done the following:
set setUserInteractionEnabled to YES for both `UIImageView and parent
view .
set setMultipleTouchEnabled to YES for UIImageView.
Tried subclassing UIImageView, didn't help any.
Attaching some code below, in this code I initialize both a UIImageView and UILabel, the label works fine in terms of firing events. I tried keeping out irrelevant code.
UIImageView *single_view = [[UIImageView alloc]initWithFrame:CGRectMake(200, 200, 100, 100)];
single_view.image = img;
single_view.layer.zPosition = 4;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[single_view addGestureRecognizer:singleTap];
[single_view setMultipleTouchEnabled:YES];
[single_view setUserInteractionEnabled:YES];
[self.myScrollView addSubview:single_view];
self.myScrollView.userInteractionEnabled = YES;
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
testLabel.backgroundColor = [UIColor redColor];
[self.myScrollView addSubview:testLabel];
[testLabel addGestureRecognizer:singleTap];
[testLabel setMultipleTouchEnabled:YES];
[testLabel setUserInteractionEnabled:YES];
testLabel.layer.zPosition = 4;
And the method which handles the event:
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
UIView *tappedView = [gesture.view hitTest:[gesture locationInView:gesture.view] withEvent:nil];
NSLog(#"Touch event on view: %#", [tappedView class]);
}
As said, the label tap is received.
Instead of making a touchable UIImageView then placing it on the navbar, you should just create a UIBarButtonItem, which you make out of a UIImageView.
First make the image view:
UIImageView *yourImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"nameOfYourImage.png"]];
Then make the barbutton item out of your image view:
UIBarButtonItem *yourBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:yourImageView];
Then add the bar button item to your navigation bar:
self.navigationItem.rightBarButtonItem = yourBarButtonItem;
Remember that this code goes into the view controller which is inside a navigation controller viewcontroller array. So basically, this "touchable image-looking bar button item" will only appear in the navigation bar when this view controller when it's being shown. When you push another view controller, this navigation bar button item will disappear.
You might want to override the touchesBegan:withEvent: method of the UIView (or subclass) that contains your UIImageView subview.
Within this method, test if any of the UITouch touches fall inside the bounds of the UIImageView instance (let's say it is called imageView).
That is, does the CGPoint element [touch locationInView] intersect with with the CGRect element [imageView bounds]? Look into the function CGRectContainsPoint to run this test.
First, you should place an UIButton and then either you can add a background image for this button, or you need to place an UIImageView over the button.
Or:
You can add the tap gesture to a UIImageView so that get the click action when tap on the UIImageView.
For those of you looking for a Swift 4 solution to this answer, you can use the following to detect a touch event on a UIImageView.
let gestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageViewTapped))
imageView.addGestureRecognizer(gestureRecognizer)
imageView.isUserInteractionEnabled = true
You will then need to define your selector as follows:
#objc func imageViewTapped() {
// Image has been tapped
}
Add gesture on that view. Add an image into that view, and then it would be detecting a gesture on the image too. You could try with the delegate method of the touch event. Then in that case it also might be detecting.

Resources