Detect provenance cell of an UIGestureRecognizer in a TableView - ios

I've a dynamic TableView, in every cell there's a MKMapView. I need that, when user tap the map (exclusively the map), app displays a new controller with expanded map.
I started placing an UITapGestureRecognizer on the map but I discovered that, from iOS 9 it doesn't works, so I followed this https://stackoverflow.com/a/35377200/2085352 and it works fine; trouble is that I can't find a way to detect from which cell does UITapGestureRecognizer come from.
I tried assigning a tag to every UITapGestureRecognizer but seems not possible, so what can I do?

If you are using the solution you liked to, you can determine the cell from the UITapGestureRecognizer passed into the function in step 4:
func imgFaild_Click(sender: UITapGestureRecognizer) {
let location = sender.locationInView(self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(location)
//do something with the indexPath
}

Related

How can I get a Table View to register taps when each cell has an Image View covering it?

I've been trying to create table view cells each with a UIImageView serving as a background for them. However, when I tap on each cell the table view will not register the click and will not transition to the view controller I have hooked up, even while I'm using the didSelectRowAtIndexPath function.
I realize it's probably an issue with the ImageView obstructing the table views ability to register the cell tap. The cells will transition however when I drag my finger/mouse on it from left to right, just not on taps. I tried to use a Tap Gesture Recognizer on the Image View however it only worked for the cell at the very top and not all of them. How do I tackle this issue?
Here is an image of the table view cells so you have an idea of what I'm working with: http://imgur.com/a/Ku4uD. Thank you!
If you uncheck User Interaction Enabled on your Image View, the problem should be solved. When running into a problem always check the user interaction of the most child view and work your way up.
One trick I have also learned is to create a subclass of a child and override touchesShouldCancel like so:
override func touchesShouldCancel(in view: UIView) -> Bool {
print("touchesShouldCancel")
//Run extra code that you want when the user selects this view
//then still retrieve the tap by its parent.
return false
}
I am unsure of exactly what your problem is, but I would delete whatever segue that you have, add a new one by dragging from the yellow circle on the left side of the center portion of the top of your tableView ViewController inside the storyboard, to the viewController that you desire it to segue to. Give the segue an appropriate identifier, and then inside your tableView class under tableView didSelectRow add performSegue(withIdentifier: "ChosenIdentifier", sender: indexPath)
Then in prepare forSegue add in:
if let vc = sender.destination as? TheViewControllerYouAreSegueingTo {
if let indexPath = sender as? IndexPath {
vc.variableIdentifyingWhatCellWasClicked = indexPath.row
}
}
with whatever adjustment is needed to meet your specific needs.

Is it possible to disable didSelectRowAtIndexPath in a part of row in UITableView?

I have a UITablaView in my Objective C application. I have the custom cells with a label and a UIImageView. I want to disable a part of the rows, to disable didSelectRowAtIndexPath when users click on this row's part.
I want this:
Is it possible?
Here is the simple and the most elegant solution that I can think off.
I believe you must be having a CustomCell, which holds the IBOutlet to imageView on the left side :) You can make use of hitTest method to solve your problem :)
In your CustomCell lets assume it to be MyTestCell class write this,
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if self.myImageView.frame.contains(point) {
return nil
}
return super.hitTest(point, with: event)
}
Where myImageView is the IBOulet of imageView on the left hand side of your cell :)
All am doing is checking where did user tap, if the touch point is within the frame of cells imageView you return nil as the view. When you return nil touch event stops propagating to its parent views and finally will never reach cell hence didSelectRowAtIndexPath never called,
On the other hand you should handover touch to the next view and you do it simply by calling same method on its super iOS will eventually trace it back to cell and triggers didSelectRowAtIndexPath
Hope it helps :)
You can do a simple trick (without the need of writing code) to solve this issue, by adding a button that covers the part that you want to disable the selection of it. Obviously, the button should not have any text or background color (it should be clear color), also make sure to add suitable constraints for making sure that is covered the wanted part of the cell.
So when tapping on the button, nothing should happen and didselectRow should not get called because the actual touching event should be referred to the button, not to the row.
Hope this helped.
This is very simple trick,
Add a button on profile image part, means on red part as shown in picture (provided by you). And don't do on click on button click.
Happy Coding!!!!
Simply put the button over Green area and set tag for each button. Onclick you can perform your functionality using tag. Like this
inside
func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let obj: AnyObject = self.dataList.objectAtIndex(indexPath.row);
cell?.populateCellWithData(obj, indexPath: indexPath)
cell?.destinationLabel.userInteractionEnabled = true
let destRecognizer : UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "DestLabelTapped:")
destRecognizer.numberOfTapsRequired = 1
destRecognizer.delegate = self
cell?.destinationLabel.addGestureRecognizer(destRecognizer)
}
and in DestLabelTapped you can peform your functionlity
Another way
Just set two Tableview and scroll them side by side and one table is selectable and another is not. (don't do this)
In my understanding the tricks with buttons and other UIElements that are covering the content are not the right way to solve the target. As you will need extra manipulations with them in Storyboard, if you will need to make dynamically content, if you will work with constraints and many more situations where you will need to control your content and + the artificial cover. There are few things to do:
Set UITableView selection to No Selection
Put the second part that you want to be active in UIView. This UIView will be the content container.
Add UITapGestureRecognizer to UIView
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(selectCellAction:)];
Add IBAction where you could do all you need.
- (IBAction)selectCellAction:(id)sender
{
// do what you need
}
And thats all.
You may simply do change the image view width constraints to 0. Where you want to action is performed. As for example:
1) If you use a button that cover the image.
2) If you take a navigation bar then you there take a button and perform the action.
hope this will help.

UICollectionView didselect and double tap conflict

There are two actions I tried to do.
Single tap which is select the cell to push to a new view controller.
Double tap to animate the cell.
I registered a double tap gesture and set doubleTapGesture.delaysTouchesBegan to ture. The single tap action is just a segue from cell to another viewcontroller.
However, there is a 0.5s delay if user single tap the cell to move to another view. The problem is the system wait for double tap gesture. If I remove the delaysTouchesBegan, it only recognize the did select cell function.
How can I reduce the delay?
Please add this line
tapgesture.delaysTouchesBegan = YES;
Assume there is a view (V) with UICollectionView (CV) inside it. Add double tap gesture to the V with settings:
doubleTap.numberOfTapsRequired = 2
doubleTap.delaysTouchesBegan = true
doubleTap.cancelsTouchesInView = true
Implement the didSelect of the CV.
It would be work separately the didSelect and the double tap. However because of delaysTouchesBegan it would be the delay before didSelect would fire.

Swift 2 button in UITableViewCell

I'm trying to figure out how to know which cell got it's button tapped.
I have a download button in each cell, and I need to know which cell's button got pressed so I can start a download of the correct item.
I have done it before in OBJ-C using blocks, but just can't get it together in Swift 2.
Anyone out there with a bit of code to share?
You can still use your objective-c approach (blocks == swift closures).
There is a lot of ways to do what you need.
You can detect which row was pressed with this:
func buttonTapped(sender:UIButton)
{
let touchPoint = sender.convertPoint(CGPoint.zero, toView:tableView); // get the location of the button inside the tableview
let indexPath = tableView.indexPathForRowAtPoint(touchPoint); // ask tableview which row is at this point
println(indexPath); // it's works! :)
}
Hope it helps.

Swift - Adding long press gesture recognizer in custom cell

So I have a custom cell class and a xib file for my cells in my tableview, and I want to add a long press recognition to the custom cell.
I tried to drag and drop the long press recognizer to the cell in the xib-file, make the file's owner the gesture's delegate, and then "drag and add" it from the document outline to the custom class swift-file. I also added the UIGestureRecognizerDelegate to the custom cell class.
Now when I run the app I get a Thread 1: signal SIGABRT error, and honestly I have no idea why. This is the first time I use the gesture recognizer so sorry if there's an obvious mistake or something I should've done.
Any suggestions on how to proceed would be appreciated.
EDIT: As Logan suggested I undid everything that was done and followed his steps. The code in my custom class now looks like this:
#IBAction func pressed(sender: AnyObject) {
func handleLongPress(sender: UILongPressGestureRecognizer) {
if sender.state == .Began {
println("Received longPress!")
}
}
}
But I still get the error. What I noticed is that if I just add the gesture to the xib-file and run the app, I get the error. I don't know if that is because I haven't connected it to the custom class file yet, but I thought I'd just throw it out there.
EDIT 2: After changing my code to this:
#IBAction func pressed(sender: UILongPressGestureRecognizer) {
if sender.state == .Began {
println("Received longPress!")
}
}
I still get the error.
I don't know if I made this clear, but I can't even load the screen, it just crashes right away. So I'm thinking this is a delegation/reference issue, here's how my references are:
1) I set the class of my xib-file owner to the custom cell class.
2) I dragged the gesture recognizer on the cell.
3) I dragged the gesture object to the file-owner so that the file owner is its delegate.
4) I added the code from above in my custom class.
5) I dragged the gesture object to the file-owner so that the gesture is "connected to the code" in the custom class.
These are all my steps, and as I said, I suspect there's a delegate issue somewhere.
I had a similar issue. The problem is that when you add a gesture recognizer to the xib file, there are multiple objects (your tableview cell and the gesture recognizer) and the tableview datasource cannot handle this. The error describes the problem correctly. I moved my tableview cell to the main storyboard instead of keeping it in a separate xib file to resolve this issue.
reason: 'invalid nib registered for identifier (CELL) - nib must contain exactly one top level object which must be a UITableViewCell instance'
Another solution to your problem would be to create the gesture recognizer in code like:
self.tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(tapFired:)];
in the awakeFromNib for the custom table view cell.
I just think the basic issue is that you cannot add gesture recognizers in a table view cell xib and then have the tableview data source load the cell.
1) I set the class of my xib-file owner to the custom cell class.
You are wrong at the very beginning. A UITableViewCell is a subclass of UIView. So you should set View to the custom cell class, not the file's owner. The file's owner should be NSObject.
You can only set file's owner as your custom class if it is the subclass of UIViewController.

Resources