collectionView is not showing in UITableViewController - ios

I want to show a UICollectionView in a UITableViewController class. I have seen videos and codes of that working, but apparently it is not working in Swift 5 anymore or at least I don't know how to set it up in Swift 5. I do everything programmatically. This is the function I am calling in my viewDidLoad() but it doesn't seem to be working:
func configureCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
let frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height - (tabBarController?.tabBar.frame.height)! - (navigationController?.navigationBar.frame.height)!)
collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.alwaysBounceVertical = true
collectionView.backgroundColor = .white
collectionView.register(SearchCell.self, forCellWithReuseIdentifier: "SearchCell")
tableView.addSubview(collectionView)
tableView.separatorColor = .clear
}
I am also calling these collectionView functions:
minimumInteritemSpacingForSectionAt
minimumLineSpacingForSectionAt
sizeForItemAt
numberOfItemsInSection
cellForItemAt
didSelectItemAt
What can I do to solve my problem?

set it up like this
collectionView.backgroundColor = .black, can you see the black background?

Related

Create cell dynamic width UICollectionViewCell

I have a problem with UICollectionViewCell.
How can I make the cell width the same on all screens?
on iPhone 13pro max, everything looks great
on iPhone se, cells in one line
Here I configure collectionView
private func makeCollectionView() -> UICollectionView {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: 190, height: 174)
layout.sectionInset = UIEdgeInsets(top: 20, left: 8, bottom: 16, right: 8)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(MenuCollectionViewCell.self, forCellWithReuseIdentifier: MenuCollectionViewCell.reuseIdentifer)
collectionView.backgroundColor = .clear
collectionView.dataSource = self
collectionView.delegate = self
collectionView.isScrollEnabled = false
collectionView.showsVerticalScrollIndicator = false
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}
How can I implement one size for all screens?
I solved the problem!
I did not calculate the cell size correctly.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let flowayout = collectionViewLayout as? UICollectionViewFlowLayout
let space: CGFloat = (flowayout?.minimumInteritemSpacing ?? 0.0) + (flowayout?.sectionInset.left ?? 0.0) + (flowayout?.sectionInset.right ?? 0.0)
let size: CGFloat = (collectionView.frame.size.width - space) / 2.0
return CGSize(width: size, height: size)
}

CollectionViewCells don't appear programmatically - Swift 5

I want to show a collectionView that appears with animation after hitting a button.
The collectionView appears correctly but the collectionViewCells inside don't.
I have set the UICollectionViewDelegate and UICollectionViewDatasource methods correctly but they aren't called (tested with breakPoints).
I'm doing everything programmatically so I also had to register the SettingCell which is a common UICollectionViewCell to the respective cellID.
Also I thought there could be a problem since I was setting the delegate and datasource too late but I don't think so since they are set at the beginning in the init of the mother class.
class SettingsLauncer : NSObject, UICollectionViewDelegate, UICollectionViewDataSource{
var collectionView : UICollectionView = {
let layout = UICollectionViewLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
return cv
}()
let CelliD = "CelliD"
func handleMoreButton(){
//creating and adding View
if let windowView = UIApplication.shared.keyWindow {
let width = UIScreen.main.bounds.width
let height = UIScreen.main.bounds.height
let heightCollectionView = CGFloat(300)
let myHeight = height - heightCollectionView
collectionView.frame = CGRect(x: 0, y: height, width: width, height: 0)
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {
windowView.addSubview(self.collectionView)
self.collectionView.frame = CGRect(x: 0, y: myHeight, width: width, height: heightCollectionView)
}, completion: nil)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CelliD, for: indexPath)
return cell
}
override init(){
super.init()
collectionView.register(SettingCell.self, forCellWithReuseIdentifier: CelliD)
collectionView.delegate = self
collectionView.delegate = self
}
}
please add these two lines in your init method
self.collectionView.delegate = self
self.collectionView.dataSource = yourDataSource
currently you are having
collectionView.delegate = self
collectionView.delegate = self
Also make your collectionView lazy ... and assign delgates there
private lazy var collectionView : UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.delegate = self
cv.dataSource = yourDataSource
cv.translatesAutoresizingMaskIntoConstraints = false
return cv
}()

Reuse identifier when using two different collection views

Riddle me this. I have a view that I'm implementing two different collection views on. The two collection views are setup nearly identically.
When I add both to my view, my app calls an error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier CollectionViewPantsCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
Which doesn't make sense, as I registered it the exact same as my CollectionViewShirtCell.
To debug, I removed the pants collection, and rewrote my "cellForItemAt" method to be really simple. It worked fine with one collectionView.
So, what is the difference? I've added some notes in caps in the code.
import UIKit
class HomeController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
let collectionViewShirtsIdentifier = "CollectionViewShirtsCell"
let collectionViewPantsIdentifier = "CollectionViewPantsCell"
var shirtStore: ShirtStore!
var pantStore: PantStore!
public var collectionViewShirts : UICollectionView{
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height/2), collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.orange
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewShirtsIdentifier)
return collectionView
}
public var collectionViewPants : UICollectionView{
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height/2), collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.blue
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewPantsIdentifier)
return collectionView
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Hanger"
self.view.addSubview(collectionViewShirts)
///... CANT ADD THE SECOND COLLECTION????
// self.view.addSubview(collectionViewPants)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionViewShirts {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewShirtsIdentifier, for: indexPath as IndexPath)
return cell
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewPantsIdentifier, for: indexPath as IndexPath)
return cell
}
}
///... THIS VERSION WORKS IF I ONLY TRY TO MANIPULATE ONE COLLECTION
// func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewShirtsCell", for: indexPath as IndexPath)
//
// return cell
// }
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
if(collectionView == collectionViewShirts)
{
print(shirtStore.allShirts.count)
return shirtStore.allShirts.count
}
else if (collectionView == collectionViewPants)
{
return pantStore.allPants.count
}
else
{
return 5//shoeStore.allShoes.count
}
}
}
The way you are setting up your collectionViewShirts and collectionViewPants variables is incorrect. As a result, the if test in cellForItemAt: is falling through to the else and you are attempting to dequeue a 'pants' cell for the 'shirts' collection view.
You need to declare your collection views properly:
public var collectionViewShirts : UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height/2), collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.orange
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewShirtsIdentifier)
return collectionView
}()
public var collectionViewPants : UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height/2), collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.blue
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewPantsIdentifier)
return collectionView
}()
Note the = and the () at the end of the closure. This tells Swift to assign the value returned by invoking the anonymous function.
I would also suggest that you use constraints rather than setting the frame directly, as this won't work with view rotation and the frame won't be set correctly at the time you are initialising the collection views, as the view frame is only set when viewDidLayoutSubviews is called.
As I mentioned earlier, doing this sort of stuff in Storyboard is much simpler.

UICollectionViewFlowLayout one row/section horizontal

I have seen so many ways to get a carousel/one row/section in UICollectionView. But non is working probably, do you have a way.
I have the following:
#IBAction func openCollectionView(_ sender: Any) {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 50, height: self.view.frame.height)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView!.delegate = self
collectionView!.dataSource = self
collectionView!.register(PDCollectionViewCell.self, forCellWithReuseIdentifier: "cellIdentifier")
collectionView?.contentOffset.x = 20
collectionView?.reloadData()
collectionView?.layoutIfNeeded()
collectionView!.addBlurEffect()
self.view.addSubview(collectionView!)
}
Ok - simple enough:
layout.itemSize = CGSize(width: (self.view.frame.size.width/2)+50, height: (self.view.frame.size.height/2)+50)
And for more complex cells:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: 100, height: 100)
}

How to set the collection view cell size exactly equal to the collection view in iOS?

I want to set a collection view where it is only displayed one element at the time and it scrolls horizontally. I want to know how to set the same size for both if the collection view has equal width with the superview (phone size).
Any help will be really appreciated.
Simple answer :
Add UICollectionViewDelegateFlowLayout to your class
and then use this method:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: yourCollectionView.bounds.width, height: yourCollectionView.bounds.height)
}
to make it horizontal:
if you want to add it programmatically you can try this:
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.delegate = self
cv.dataSource = self
cv.isPagingEnabled = true
cv.showsHorizontalScrollIndicator = false
return cv
}()
Try this code:
To set collectionView scroll Direction Programmically.
override func viewDidLoad() {
super.viewDidLoad()
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
}
}
To set collectionView layout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.invalidateLayout()
return CGSize(width: self.view.frame.width, height:(self.view.frame.height) // Set your item size here
}
Note: Layout works tested in Swift 3. But, I want you to consider using page view instead.If you not passing any data from CollectionView.

Resources