Creating a horizontal scrolling menu - ios

I am trying to create a menu where top horizontal scrolling view contains the menu categories. When I tap on one of the menu categories, ads related to the category appears.
When First is selected
--**First**---|--Second--|---Third--|--Fourth--| (scrolling categories)
------------------------------------------------------------------
\\\FirstA\\\ \\\FirstB\\\ \\\FirstC\\\ \\\FirstD\\\
\\\FirstA\\\ \\\FirstB\\\ \\\FirstC\\\ \\\FirstD\\\
------------------------------------------------------------------
When Second is selected
--First---|--**Second**--|---Third--|--Fourth--| (scrolling categories)
------------------------------------------------------------------
\\\SecondA\\\ \\\SecondB\\\ \\\SecondC\\\ \\\SecondD\\\
\\\SecondA\\\ \\\SecondB\\\ \\\SecondC\\\ \\\SecondD\\\
------------------------------------------------------------------
When I tap on First Category, data related to first comes as a collectionView. Similarly, when I tap on second Category, data related to second comes in the UICollectionView.
Now I am thinking of doing it in a UITableViewCell with two UICollectionViews. First UICollectionView will contain categories and second UICollectionView will contain data related to categories.
But I have never used two UICollectionViews in a single UITableViewCell.
So I am asking is it the correct approach for this type of requirement or should I do it in some other manner.

You could subclass an UITableViewCell, add UICollectionView as subview, conform UICollectionViewDataSource and UICollectionViewDelegate
here's sample code using xib
class CollectionViewTVC: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
}
extension CollectionViewTVC: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return items
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
// return size
}
}
extension CollectionViewTVC: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// select cell action
}
}

Why don’t you use two table view cells, one for every collectionViewu?

Related

Swift UICollectionView Cell being rendered twice

I am writing a customer calendar as a challenge for me to practice UICollectionView. This issue has been puzzled me for few days. So the problem is when it reuses the cell, the load data source function has been called twice or three times, then it leads to:
Sometimes it's called three times and my calendar days become 100 110 etc.
Here is the delegate and datasource code:
extension CalendarViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.calendarPages.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CalendarCell
cell.calendarPage = self.calendarPages[self.currentPageIndex]
cell.contentView.addSubview(self.buildCalendarPage(index: indexPath.row, frame: cell.contentView.frame)) // this is where it add new month page to the calendar, and it's randomly called multiple times
print("cell called")
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
}
}
I know what's going one there, so basically I made it too complicated, there is a calendar UICollectionView in another UICollectionView, (I just want to make it scrollable), so each time when the cell is reused, I forget to reload the UI
Solution, keep only one UICollectionView, each cell is a day, and create another UICollectionViewCell class to control the reusable cell, thanks for the Babar's help

numberOfItemsInSection is called but cellForItemAt is not called UICollectionViewController

This maybe a duplicate post. But I haven't found any solution in the answers given in previous questions.
Basic checks from my side that I have done.
No errors on the constraint that I have put on CollectionView and CollectionViewCell.
When numberofitemsinsection is called, it always returns more than 0.
Reusable identifier is tagged for both CollectionView and CollectionViewCell
All links for ui objects are at place.
CollectionViewCell size is set as default.
Some more information on my code.
class StickerGridCollectionViewController: UICollectionViewController{
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return stickerPackList.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
/*some code*/
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
/*some code*/
}
}
I checked all the answers here, but didn't find my answer yet.
Any clue why I might be getting this issue?
Update
When I open debug view hierarchy, I find out that collectionview is taking correct area, but views which were supposed to be inside collectionview are flowing outside and acting abnormally.
Moreover I see UICollectionView inside UiCollectionView.
Any reason, why this abnormal behaviour might occur?

Method not fired in UICollectionView when added within a UIStackview

I have added a UICollectionVIew to a vertical Stack View. I connected both datasource and Delegate from storyboard and added the delegate/datasource from the code as well.
However, the following method is not being called at all:
internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { ... }
But, the methods
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
are being called.
So, I moved the UICollectionVIew out of the vertical Stack View and it was working then. But, the method is not being called when the UICollectionVIew is in the vertical Stack View.
How can I solve this?
Same happen with me in past with TableView but not with UIStackView
If numberOfSections and numberOfItemsInSection called and cellForItemAt not called then only possible reason your CollectionView height is 0
Because of that your cell didn't get enough space to show cell
You can Check same thing by adding height of your collection view to 0
in to the case where you said I moved the UICollectionVIew out of the vertical Stack View and it was working then.

How do I create a 'sticky' horizontal scrolling effect with collection view Swift 3

I have a collection view with multiple cells. Users can scroll horizontality. However, I want it to center the nearest cell once the user lets go. Or, if not, have some form of paging but for individual cells. I'm making basically an icon/profile picture picker.
#IBOutlet weak var profilePicScrollView: UIScrollView!
var profilePicsArray = [#imageLiteral(resourceName: "sample_user_photo"), #imageLiteral(resourceName: "settings_icon"), #imageLiteral(resourceName: "usernametextfield_dark")]
#IBOutlet weak var profilePicCollectionView: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return profilePicsArray.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionat section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageViewCellReuseID", for: indexPath) as! SettingsCollectionViewCell
cell.imageInCollection.image = profilePicsArray[indexPath.row]
cell.imageInCollection.backgroundColor = UIColor.getRandomColor()
return cell
}
Assuming your collection view's cells are equal to the width of your collection view's bounds, you could just set the collection view's isPagingEnabled property to true – considering UICollectionView inherits from UIScrollView.
If that's not the case, then you might try the following:
First, implement the scrollViewDidEndDragging(_:willDecelerate:) method of your collection view's delegate. Then, in that method's body, determine which cell in collectionView.visibleCells is most visible by comparing each of their centers against your collection view's center. Once you find your collection view's most visible cell, scroll to it by calling scrollToItem(at:at:animated:).

How to prevent dequeued collection view cells from overlapping each other?

I've been trying to set up a collection view where I have the user submit several strings which I toss in an array and call back through the collection view's cellForItemAt function. However, whenever I add a row to to the top of the collection view, it adds the cell label literally on top of the last cell label so they stack like this. Notice how every new word I add includes all the other previous words in the rendering.
The code I have at cellForItemAt is
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "InterestsCell", for: indexPath) as? InterestsCell {
cell.interestLabel.text = array[indexPath.row]
return cell
} else {
return UICollectionViewCell()
}
}
and the code I have when the add button is pressed is
func addTapped() {
let interest = interestsField.text
array.insert(interest!, at: 0)
interestsField.text = ""
collectionView.reloadData()
}
I'm not sure what's going on. I looked everywhere and tried to use prepareForReuse() but it didn't seem to work. I later tried deleting cells by calling didSelect and the cells would not disappear again. Any help is appreciated!
This is the code I have in my custom collection view cell implementation in the event that this is causing the error
To do this paste these functions in your project
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 1
}
you can play around with the values :)
This can be easily implemented using UITableView. So try to use UITableView instead of UICollectionView.
It looks like you're adding a new label every time you set the text. If you want to lazily load the UILabel you need to add lazy
lazy var interestLabel: UILabel = {
...
}()
I wouldn't do it this way though, I would create a reference to the label
weak var interestLabel: UILabel!
Then add the label in your setupViews method
func setupViews() {
...
let interestLabel = UILabel()
...
contentView.addSubview(interestLabel)
self.interestLabel = interestLabel
}

Resources