didSelectItemAtIndexPath not called with multiple collection views on same screen - ios

I have 2 collection views on the same screen, and I have the data source and delegate implemented for both in the same view controller. However, the delegate methods such as didSelectItemAtIndexPath is only called for one.
Other info:
Both collection views have a cell with an image.
AllowSelection and UserInteractionEnabled is set to true in both collection views
User interaction enabled on the images
Delegate and data source are set on the storyboard from both collection views to the view controller
Collection views are displayed properly
Both collection views have the same setup, yet only one delegate works. Would you have any clues what could be setting this up?
The collection views are inside a view that has a scroll view. Could this be somehow related?
EDIT 2:
Project with the same problem: https://github.com/iagomr/ProblemWithAutoLayout
EDIT 1:
Somehow this has to do with autolayout constraints, because if I pin the bottom collection view to the bottom of the screen instead of the bottom of other collection view, it starts working.
This is all due to the fact that I need to build a tall screen, and added everything into a view inside a scroll view 1000 points tall.
Code:
//MARK: - CollectionView Delegate
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
println("Called")
}
//MARK: - CollectionView DataSource
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == thisCV {
return 1
} else if collectionView == thisOtherCV{
return 1
}
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if collectionView == "thisCV" {
if let thisCell = collectionView.dequeueReusableCellWithReuseIdentifier("thisCell", forIndexPath: indexPath) as? thisCollectionViewCell {
thisCell.image = image
return thisCell
}
} else if collectionView == "thisOtherCV"{
if let thisOtherCell = collectionView.dequeueReusableCellWithReuseIdentifier("thisOtherCell", forIndexPath: indexPath) as? OtherCollectionViewCell {
thisOtherCell.image = image
return thisOtherCell
}
}
return UICollectionViewCell()
}

I can confirm that didSelectItem is not getting called. If constant for top-bottom constraint between two collection views is changed from 501 to 0 it is working.
This problem is most likely related to the fact that you have two scroll views (collection views) inside of another scroll view. Overall, I would say, that you should modify your UI. I would suggest two ways of fixing it
Using single collection view
Use just one collection view with different sections for different content. Also, do NOT embed it in the scroll view - collection view already has a scroll view so you should be able to scroll easily. You can also dequeue different class of cells for different sections so you should be able to do everything which you want to do now.
If you want a starting point, here is a good tutorial which should help you with that.
Using scroll view
If you want to setup your UI in Interface Builder remove both collection views and simply add all of your UI inside of scroll view. Place UIButton in places where you want clicking to produce action.
You can even assign the same action to each button and then differentiate which one was triggered by assigning custom tags to each of them.

Related

What are the differences between remembersLastFocusedIndexPath and indexPathForPreferredFocusedView(in:) methods?

I have made a TvOS app which has 2 collection views they will be scrollable horizontally.
Now both of them have items which open corresponding cell's detail page.
That new page is pushed on navigation stack, when I come back I want my focus to remain on same cell of the collection view which opened the new page.
So, I found and tried two methods.
Method 1:
Setting collectionView.remembersLastFocusedIndexPath = true for both collection views
Method 2:
Using indexPathForPreferredFocusedView(in:) in delegate of both collection views.
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// SOME WORK
focusedCellIndexPath = indexPath
}
override func indexPathForPreferredFocusedView(in collectionView: UICollectionView) -> IndexPath? {
return focusedCellIndexPath
}
Now when I used Method 1:
Say I have 10 cells in both collection view.
I was on cell 2 in first collection view, then I press down and scroll till the end on the second collection view and I press up then I go back to second cell of first collection view.
But when I used Mewthod 2:
When I press up then I don't go on second cell of first collection view but go on the cell just above currently focused cell of second collection view.
I want to know why they both behaved differently, looking at official documentation of method used in method2 in its discussion section it looks both things should behave similarly, but that is not the case here.

Tableview Controller with a dynamic tableview in its static cell

I have a form inside a tableview controller. The last 3 parts of the form are address textfield, map and a save button. When the user begins typing on the address field a uitableview will slide up covering the map to display different results. When I set the child tableview mapTableview's delegate and datasource to self this is when the problem would start, the screen just displays a white background. I tried different solutions but they don't work. Also tried this one but the data source must be coming from the tableview controller itself. Dynamic Tableview inside a Static tableview Cell
When I create an array of strings in the class Datasource and put the following codes below in my tableview controller, the strings get displayed in the mapTableView.
var dataSource = DataSource()
mapTableView.delegate = dataSource
maptTableView.delegate = dataSource
But since the data source must be coming from tableview controller, I tried to put the code below, and many other things as suggested in other posts, in my table view controller but the screen won't display anything, just all white. And I get these errors:
UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window)
Detected a case where constraints ambiguously suggest a height of zero for a table view cell's content view. We're considering the collapse unintentional and using standard height instead
extension EditProfileTableViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pois.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellResult", for: indexPath) as! MapTableViewCell
let poi = pois[indexPath.row]
cell.textLabel?.text = poi.title
cell.detailTextLabel?.text = poi.subtitle
cell.detailTextLabel?.numberOfLines = 0
return cell
}
}
and in my viewDidLoad
tableView.estimatedRowHeight = 60.0;
tableView.rowHeight = UITableView.automaticDimension;
How to correctly put a tableview inside a static tableview cell? Please help
You should create another table view controller for the inner table view. Let's call it MapTableViewController.
Add Container View into the static cell in storyboard.
Add Table View Controller into that container view, set its class to MapTableViewController.
Put all datasource/delegate methods for mapTableView from the EditProfileTableViewController into MapTableViewController. After that, EditProfileTableViewController should have no UITableViewDataSource and UITableViewDelegate protocol methods at all.

Customizing collection views and creating space between the collection view’s cells

I’m trying to create this relationship that the pictures below depict of Parent -> Children -> Children -> etc. . . I’m trying to use a vertical collection view for the Parent collection view and then nested horizontal collection views for the children. But I’m struggling with moving the collection views cells down when the “View Children Button” is clicked. I thought I could do something like this when the button is clicked:
#IBAction func showChildrenBtnClicked(_ sender: Any) {
collectionView.contentInset.bottom = 200
collectionView.reloadData()
}
but this doesn’t seem to do anything. Does anyone know how to add empty space inside the collection view so that I could then create a horizontal collection view to hold the children elements.
These are some mock images of the behavior I'm trying to achieve:
Step 1)
Step 2)
Step 3)
Step 4)
Step 5)
Thank you in advance.
First take all the view as collection view.
When ViewchildrenButton get tapped, delegate it to the parent collection view controller class, and there
if let flowLayout = metaMoreCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.invalidateLayout()
}
This will call the
collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
and give the updated size there.

Multiple UICollectionViews in ViewController | Would not call one CollectionViews Delegate methods

SO I have two UICollectionViews in my UIViewController in Storyboard and both are linked with delegate and datasource to my ViewController. All the associated UICollectionView delegate methods are implemented and checks for the UICollectionViews are implemented. But it's so frustrating that one UICollectionView is getting catered while the other one is getting completely ignored. I have scratched my head in all the available aspects but it is kind of putting me further towards the edge, please help.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.variantsCollectionView {
// let count = (item?.variant_groups?.count)!
return 1
} else {
return 2//(item?.extra_groups?.count)!
}
}
and
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
if collectionView == self.variantsCollectionView {
//IT DOESNT EVEN COME HERE AT ALL
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell_variant", for: indexPath)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
//HERE IT COMES ALWAYS FOR THE NUMBER OF CELLS
return cell
}
}
Whereas the UICollectionViews are connected like this:
and:
Please please help. Thank you so much
Via comments the TS found solution by following these steps:
Ensure both collection views have non-nil data sources (and delegates).
Check that data source methods are executed for both collection view.
Check that both collection views' cells have valid size.
Finally the problem was found after checking the heights of each collection view inside stack view.
basically CollectionView has a specific height whereas
VariantCollectionView didnt, and both were in a stackView. When first
was created in view it took up the entire size where as the other one
kind of actually disappeared. Hence the issue.

UITableViewController as subview swift

I'm trying to make my first app and I'm stuck at this point.
My app looks like snapchat, a horizontal scrollview and the left part is composed of a tableview.
So, in this left part I put as a subview a tableViewController. The problem is the cells are always empty ! The table view is showing with the right cell's height but cells are empty.
I'm sure you can help me, thank you !
I make the subview here
Link with cells here
Please be ensure that override necessary methods in table view controller and balance calls in adding child view controller code rutin.One more last thing when adding child view controller you should provide correct size to controller view.
for adding table view controller as a child view controller
guard let list = R.storyboard.dashboard.addressesController()else {
return
}
self.list = list
self.addChildViewController(list)
self.scroll.addSubview(list.view)
list.didMoveToParentViewController(self)
list.tableView.layoutIfNeeded()
list.view.snp_makeConstraints(closure: {
(make) in
make.left.equalTo(self.view).offset(10)
make.right.equalTo(self.view).offset(-10)
make.bottom.equalTo(self.scroll)
make.height.equalTo(list.tableView.contentSize.height)
make.top.equalTo(authorizedTop.snp_bottom).offset(10)
})
for extending table view controller
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(self.cellIdentifier) as UITableViewCell
cell.textLabel?.text = self.tableData[indexPath.row]
return cell
}
I know this isn't an answer to you question, but I have a suggestion which might help you in the long run, and maybe help you debug your current problem:
How about splitting the tableViews' logic into separate UITableViewControllers? That way you avoid some gigantic common UIViewController. You can use the Container View in your storyboard, which can embed a UIViewController.

Resources