I have a UICollectionView. Its cell has a UICollectionView inside of it.
I can detect when the cell containing the collectionView is tapped (via didSelectItemAtIndexPath). However, I cannot detect when the cells of the collectionView inside the cell (as depicted by the individual sun icons) are tapped.
User-interaction is enabled on everything. And I've tried overriding the hitTest of the collectionView as described here.
Update: I tried this again in a simple test project and it worked fine. However in my current project for some reason the inner-most nested collectionView (with the sun icons) does not appear in the view debugger.
Notice I made the collectionView background blue and its cells pink. And they do not appear when view debugged, although they appear in the running app?
I've done this before... but it's going to be a little hard to explain.
The short answer is TapGestures.
So I had the tableView through storyboard drawn. The collection view was added programatically.
For TableView cellforRow, I called UITableViewCell subclass. Which I passed the rootView as a delegate. Which called a CollectionViewClass. This is where the actual items for the cell are being drawn and added to the collection view. At this point I have the rootdelegate. For each item i add a tapGesture.
let tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
So each item now has a tap gesture inside it. Now in my view that was drawing i can call the rootview with which cell was tapped.
func viewTapped() {
tapDelegate?.milestoneTapped(passID) //tapDelegate = RootView
}
I hope this helps.
Once I changed from using XIBs for my cells to using regular cells from storyboard this problem did not occur.
Related
I have a UIView A, and I added a UICollectionView B to A as a subView, so now view A is B's background view. Here didSelectItemAtIndexPath will get called normally at this time. But if I add a tap gesture recognizer to View A, then didSelectItemAtIndexPath won't be called. The code is simple like below
UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap2)];
[viewA addGestureRecognizer:tap2];
How can I make didSelectItemAtIndexPath get called for this situation? My expected behavior is both tapping cell and tapping background methods get called normally and separately as they have different tap behaviors.
From Apple's documentation:
You should always attach your gesture recognizers to the collection view itself—not to a specific cell or view. The UICollectionView class is a descendant of UIScrollView, so attaching your gesture recognizers to the collection view is less likely to interfere with the other gestures that must be tracked. In addition, because the collection view has access to your data source and your layout object, you still have access to all the information you need to manipulate cells and views appropriately.
https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/IncorporatingGestureSupport/IncorporatingGestureSupport.html
I have done this and it works very well. Generally I would call indexPathForItemAtPoint: on the collectionView to get the indexPath and then get the cell from cellForItemAtIndexPath. In your case you can check to see that indexPathForItemAtPoint returns nil (ie the user is clicking on an area between the cells) and then do your code for that. You can also use UIView convertRect methods to figure out exactly where the touch it.
I have tableVC, it contains from cells with customViews.
That customViews contains from 3 imageViews, so then I click on imageView, it makes some action. To achieve it I added UITapGestureRecognizers to imageView.
Now I need to be notified then this cells are tapped in my tableVC. I get this events in didSelectRowAtIndexPath, but only if I do not touch any of imageViews with gestures.
How can I receive tap notification in my tableVC about touching my cell completely ?
If you want to get cell that is tapped - didSelectRowAtIndexPath is way to go. If you want to get the tapped image inside that cell - implement delegate for that ( https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources.html ) and do the corresponding actions. I see that you mentioned didSelectRowAtIndexPath, but I am not sure what was your problem.
Also I didn't put any code since I don't know if you are using swift or objective-c.
Generally:
Is it OK to add a UITableView as a subview of another UITableView? Or, should I create a UIView and add each UITableView to it?
Specifically:
For a ComposeTableViewController with a typeahead, like in the iPhone's native Mail app, which approach would you recommend and why?
Note: I prefer to construct things 100% programmatically (no Interface Builder).
Subclass UITableViewController.
Then, to show the typeahead results, create and add a resultsTableView as a subview of self.tableView positioned directly underneath the the cell (of self.tableView) with the typeahead text field.
The nice thing about this approach is that resultsTableView scrolls with self.tableView automatically.
But, is it OK to add a UITableView as a subview of another UITableView?
Subclass UIViewController.
Create and add tableView (custom property) as a subview of self.view.
Create and add resultsTableView also as a subview of self.view.
The annoying thing about this approach is that I have to reposition resultsTableView manually anytime self.tableView scrolls.
I think I'd prefer approach 1, but adding a UITableView as a subview of another UITableView just seems smelly to me.
TableViews cannot have subviews. You can try adding a tableview as the view of a TableViewCell, but then you have to ask yourself how it would scroll, if you tried scrolling in the subtableview would it scroll the child tableview or the parent tableview? It is much easier to present multiple tableviews within a view. This can be done easily by setting your custom viewcontroller as the datasource of both tableviews contained within its view and then comparing the tableview pointer that is sent as a parameter of the datasource method to the two tableview pointers that are IVars of your custom view controller.
Hold stuff like this in a container. Create a container view controller which only does typeahead. This container view controller will hold your main table view controller (and its table view) and it will hold the typeahead view controller (and its view).
It will keep the logic needed for the typeahead out of your main table view and as a bonus you might end up with a reusable typeahead container which could be applied to other views.
Yes it is good to go for adding UITableView in as a cell of another UITableView.
I had one issue and posted a question
Multiple Views as subviews
And requirement was like a group of controls with list of other controls. I thought that time that it will be messy if i'm going to add UITableView as a cell of UITableView.
What i found that... Boy !! it's how iOS meant to be. There is no any lag while doing this.
Tested for below functionalities:
Scrolls like a charm
Separate delegates called for each
Reordering of both UITableView cell
Swipe and remove cell
Runtime datasource update for both UITableView and reload both at the same time.
There is no any reason not to add subview UITableView.
You can do it but it is against the principle of MVC. You will be setting the delegate of a view to another view which is wrong.
I have several UITableViews which should segue further in my navigation controller. First I've created the segues directly from the table view cells. But then I've noticed that in the smaller cells if you click on the label or somewhere, this method didSelectRowAtIndexPath doesn't get triggered. Only if you click on an "empty" space in the cell.
So I've created the segue for the whole view and just called performSegueWithIdentifier in the didSelectRowAtIndexPath method.
But still the same problem. Is this only my impression that you have to click on empty parts or onto the right side of a cell to perform a segue or is something else wrong? Or how could I make the whole cell reactive?
You might try turning off User interaction enabled for the labels in your cell.
I've got a UITableView which pushes a detail view when I tap any of its cells. I'd like that segue to only occur when tapping a specific part of the cell, a UIImageView at its left side. Tapping the rest of the cell should trigger a UITapGestureRecognizer which triggers a different method.
How can I override the default tap on the UITableViewCell, so that simply tapping anywhere on the cell doesn't trigger the segue to the detail view? I still want that transition, just only triggered by the UIImageView.
I think you could achieve that by connecting the segue with the image in the prototype cell (Never tried that myself) and not with the table view.
If you don't have a prototype cell then you should programmatically invoke an IBAction type of method with the image views. Well, Image Views cannot do that. Simply abuse a UIButton of the same size, custom style and assign the image to that button. Works fine.
(It does not need to be an -(IBAction) type of method, but it does not harm and doing so ensures that everything works fine.)
Within that action method invoke the segue programmatically. The segue needs to have an ID for that which is unique within the storyboard.