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

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.

Related

is it possilbe to uiview, detect from pop navigation controller?

I have a collectionview called "A" inside another collectionView cell,
in collectionView "A"'s cell, there is uiView.
In this uiview I play some animation.
When I click collectionView "A"'s cell, It pushes navigation controller, and I stop the animation.
I want to play animation again when I pop navigation controller.
Is it possibe to uiview, detect when view is appear again?
I know uiviewcontroller has viewdidload or viewwillapper to detect, but i need uiview to know.
You'll have to keep a weak reference of that cell and you can access the specific view when you pop the view controller.
Save the index you clicked and get that specific cell using this line and play the animation collectionView.cellForItem(at: IndexPath)

Use right to left UIScreenEdgePanGestureRecognizer on UITableView that has section indexes

I want to add a UIScreenEdgePanGestureRecognizer to a UITableView so that I can edge swipe from the right side to go to the next screen in my controller hierarchy.
This works fine except when the table view has section indexes shown on the side. In that case, the section index area handles the touches, so I can't swipe from the edge. I would like to be able to support both the edge pan and the section index tap and vertical pan functionality.
I tried adding a view on top of the UITableView to handle the swipe, but then that handles all touches and the table view no longer gets anything.
Okay, so I tried a bunch of stuff and came up with a non-ideal but working solution.
The first part of the problem is that the section index is in its own view as a subview of UITableView. So it captures any touches or gesture recognizers that you might add to the UITableView.
The second problem is that the section index view is not part of the public API.
So my solution is to add a UIScreenEdgePanGestureRecognizer to the section index view.
The view is an instance of the private class UITableViewIndex. To get it I created a UITableView extension:
extension UITableView {
var sectionIndexView: UIView? {
for view in self.subviews {
if view.className() == "UITableViewIndex" {
return view
}
}
return nil
}
}
NOTE the above code is fragile and not future proof, because if Apple changes the class name or its location in the view hierarchy it will no longer work. In my case the edge swipe is a convenience feature, and there is a "Next" button at the top of the screen. In addition, most of my view controllers don't have a table index, so if it stopped working it would only be on a few screens. So if this solution doesn't work in the future then it's not a huge deal.
I also wrote an convenience function to get the edge gesture recognizer from any view:
extension UIView {
var screenEdgePanGestureRecognizer: UIScreenEdgePanGestureRecognizer? {
guard let gestures = self.gestureRecognizers else {
return nil
}
for gesture in gestures {
if let edgePan = gesture as? UIScreenEdgePanGestureRecognizer {
return edgePan
}
}
return nil
}
}
I add a UIScreenEdgePanGestureRecognizer to the UITableView in the viewDidLoad method of my view controller.
Finally, in viewDidAppear of my view controller I check to see if the gesture recognizer has been added to the section index view. If it hasn't, then I add it there. You need to do this at some point after the section index has been added to the table view - i.e. not in viewDidLoad. And you need to make sure you're not adding the gesture recognizer multiple times.

How to callback a function in tableView's Class from tableViewCell's Class

I'm having a TableView. In that tableView, I custom it's cells
like this
In this cell I have 2 part. An Image and an TextField.
It's look like facebook's post status. When I click to Image, I want to open a new ViewController and the same for TextField
But I have a problem that I can't call segue from my cell's class file.
Are there any way that I can call a function in TableViewController's class from TableViewCell's class ?
I know that I can use delegate but I don't like this way a lot, because if I do this way I have to set a lot of delegate in my project.
Are there any better way to present a new ViewController directly from TableViewCell's class
Using a delegate is a very good way to solve your problem.
If you don't like that solution then you could design a table view cell that has a closure property set by the view controller, and invokes that closure when the button is pressed.
EDIT:
Another alternative is to leave the button action empty in your custom cell, but still connect up outlets to the buttons.
Then in your cellForRow(at:) method, install an IBAction that has your view controller as the target. (Credit to #SoanSani, who's answer is below)
In that IBAction method, you can use the coordinates of the button to figure out the indexPath of the cell hat contains the button that was tapped.
I've created an extension to UITableView that lets you figure out the cell that contains any view. The code is below:
import UIKit
public extension UITableView {
/**
This method returns the indexPath of the cell that contains the specified view
- Parameter view: The view to find.
- Returns: The indexPath of the cell containing the view, or nil if it can't be found
*/
func indexPathForView(_ view: UIView) -> IndexPath? {
let origin = view.bounds.origin
let viewOrigin = self.convert(origin, from: view)
let indexPath = self.indexPathForRow(at: viewOrigin)
return indexPath
}
}
You can use delegates, but if you dont want to use delegates
while setting up the cell add target to your button tableViewController class and then you can receive all events in tableview class rather than cell class.
But this would require to add tags which you can use to differentiate which button in cell was clicked
Objective C Code
[OkBtn addTarget:self action:#selector(okButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
Swift Code
OkBtn.addTarget(self, action: #selector(ViewController.okButtonTapped), for: .TouchUpInside)

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.

How to add a view to UINavigationController that is visible above any child view

I'm creating an app which shows data in a UITableView. This data also contains location information, so I want to add a MapView to display this data. When a user taps a UITableViewCel, I need to segue to another UITableView to show the detailed data. I still want to show the MapView with the same data above this detailed data, and I still want the NavigationBar to update, i.e. the back buttons returns the user to the first UITableView.
In image form to make it easier to understand
I was thinking of making a subclass of a UINavigationController and putting the container underneath the MapView, but I don't really know where to go from there.
Have VC0 embedded in a navigation controller or subclass UINavigationController. Create an Info ViewController and push that on the navigation controller.
In your particular case you'll want to use the didSelectRowAt method from UITableViewDelegate.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// use indexPath.section and indexPath.row to use your data
let infoVC = yourInfoViewController()
infoVC.title = "Info Cell Name"
navigationController?.pushViewController(infoVC, animated: true)
}
Edit after first comment:
I'm not sure what the best way of doing this is but one way you can do it is:
Modify your table view based on what is being shown, ie: first set of data or cell detail data
Update the navigation bar's title and left bar buttons per set of data you're displaying
One of those buttons will only appear in the cell detail data set and it sets your switch back to displaying the first set of data

Resources