Adjust UICollectionView UICollectionReusableView (header) width - ios

I would like to adjust collectionview header width in iPad.
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: 668, height: 44.0)
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 50, bottom: 0, right: 50)
}
I explicitly set the width even though it's showing headerView base on collectionView width.
Current Behaviour:
Expected:

Thi is sample code to do it:
declare your collection view, register cell, register header and set constraints:
class ViewController: UIViewController {
var collectionview: UICollectionView!
var cellId = "Cell"
let headerId = "myFooterView"
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
var myUIViewArr = ["1", "2", "3", "4", "5", "6", "7"]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
layout.scrollDirection = .vertical
collectionview = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionview.dataSource = self
collectionview.delegate = self
collectionview.register(MenuCell.self, forCellWithReuseIdentifier: cellId)
collectionview.showsVerticalScrollIndicator = false
collectionview.backgroundColor = .black
collectionview.register(MyHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerId)
collectionview.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionview)
collectionview.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
collectionview.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
collectionview.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
collectionview.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
}
now set collectionView delegate and datasource method:
extension ViewController : UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return myUIViewArr.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionview.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MenuCell
cell.contentView.backgroundColor = .red
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
layout.scrollDirection = .vertical
let cellInRow = 3
let totalSpace = layout.sectionInset.left + layout.sectionInset.right + (layout.minimumInteritemSpacing * CGFloat(cellInRow - 1))
let mySize = collectionView.bounds.width - totalSpace
let size = mySize / CGFloat(cellInRow)
return CGSize(width: size, height: size)
}
//set header view height
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 44)
}
//set header view
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerId, for: indexPath) as! MyHeaderView
return view
}
}
set header class:
class MyHeaderView: UICollectionReusableView {
let labelHeader = UILabel()
let imageV: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(systemName: "arrow.right.circle.fill")
iv.contentMode = .scaleAspectFill
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
labelHeader.text = "Add Your Text here"
labelHeader.textColor = .black
labelHeader.numberOfLines = 0
labelHeader.backgroundColor = .white
labelHeader.translatesAutoresizingMaskIntoConstraints = false
imageV.tintColor = .orange
imageV.translatesAutoresizingMaskIntoConstraints = false
addSubview(imageV)
imageV.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true
imageV.heightAnchor.constraint(equalToConstant: 30).isActive = true
imageV.widthAnchor.constraint(equalToConstant: 30).isActive = true
imageV.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
addSubview(labelHeader)
labelHeader.topAnchor.constraint(equalTo: topAnchor).isActive = true
labelHeader.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
labelHeader.trailingAnchor.constraint(equalTo: imageV.leadingAnchor).isActive = true
labelHeader.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
and your cell class:
class MenuCell: UICollectionViewCell {
let containerView = UIView()
let myView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
myView.translatesAutoresizingMaskIntoConstraints = false
contentView.backgroundColor = .clear
containerView.backgroundColor = .clear
containerView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(containerView)
containerView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
containerView.addSubview(myView)
myView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
myView.heightAnchor.constraint(equalToConstant: 60).isActive = true
myView.widthAnchor.constraint(equalToConstant: 60).isActive = true
myView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
This is the result:
if you want some padding on the left of your header label in MyHeaderView simply add leading constraint constant like this:
labelHeader.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
and this is the result:

Related

Header Not Showing in UICollectionView

I've built a collection view programmatically which is working fine however I am trying to add a header but nothing is showing up at the top for the header.
Here are the lines of code I have included which I understand to be important:
collectionView.register(HeaderCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: HeaderCollectionReusableView.identifier)
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: HeaderCollectionReusableView.identifier, for: indexPath) as! HeaderCollectionReusableView
header.backgroundColor = .red
return header
}
func collectionView(_collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 100)
}
I am not sure if I am missing some important code or if something is in the wrong place?
Any help would be appreciated.
Thanks!
Declare collection view, UICollectionViewFlowLayout, cellId and headerId:
class YourController: UIViewController {
private var collectionView: UICollectionView?
let layout = UICollectionViewFlowLayout()
let cellId = "cellId"
let headerId = "headerId"
now in viewDidLoad set layout, collection and add constraints:
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: view.bounds.size.width / 2.2, height: view.bounds.size.width / 2.2) // set item size
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView?.delegate = self
collectionView?.dataSource = self
collectionView?.backgroundColor = .clear
collectionView?.register(MyCell.self, forCellWithReuseIdentifier: cellId)
collectionView?.register(MyHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerId)
collectionView?.contentInset = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
collectionView?.translatesAutoresizingMaskIntoConstraints = false
guard let collection = collectionView else { return }
view.addSubview(collection)
collection.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
collection.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
collection.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
collection.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
Now in a separate Extension (the code is much clean) conform the collection delegate and datasource:
extension YourController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MyCell
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerId, for: indexPath) as! MyHeader
header.configure()
return header
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 100)
}
}
After that set your custom cell:
class MyCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
contentView.backgroundColor = .link
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Now set the reusable view for header:
class MyHeader: UICollectionReusableView {
private let label: UILabel = {
let label = UILabel()
label.text = "This is the header"
label.textAlignment = .center
label.textColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
public func configure() {
backgroundColor = .systemGreen
addSubview(label)
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
}
This is the result:

SwipeCellKit does not swipe cell

I want to implement UITableView's UISwipeActionsConfiguration for a UICollectionView. In order to do so, I am using SwipeCellKit - github
My UICollectionView adopts to the SwipeCollectionViewCellDelegate protocol. And the cell inherits from SwipeCollectionViewCell.
ViewController with UICollectionView
class SwipeViewController: UIViewController {
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(SwipeableCollectionViewCell.self, forCellWithReuseIdentifier: SwipeableCollectionViewCell.identifier)
collectionView.showsVerticalScrollIndicator = false
collectionView.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 4, right: 0)
collectionView.backgroundColor = UIColor(white: 0.97, alpha: 1)
collectionView.dataSource = self
collectionView.delegate = self
return collectionView
}()
var items: [String] = {
var items = [String]()
for i in 1 ..< 20 {
items.append("Item \(i)")
}
return items
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
collectionView.setConstraints(topAnchor: view.topAnchor,
leadingAnchor: view.leadingAnchor,
bottomAnchor: view.bottomAnchor,
trailingAnchor: view.trailingAnchor,
leadingConstant: 10,
trailingConstant: 10)
}
}
extension SwipeViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 80)
}
}
extension SwipeViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SwipeableCollectionViewCell.identifier, for: indexPath) as! SwipeableCollectionViewCell
cell.backgroundColor = BackgroundColor.colors[indexPath.row]
cell.delegate = self
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
}
extension SwipeViewController: SwipeCollectionViewCellDelegate {
func collectionView(_ collectionView: UICollectionView, editActionsForItemAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
}
return [deleteAction]
}
}
SwipeCollectionViewCell
class SwipeableCollectionViewCell: SwipeCollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(nameLabel)
nameLabel.setConstraints(topAnchor: self.topAnchor,
leadingAnchor: self.leadingAnchor,
bottomAnchor: self.bottomAnchor,
trailingAnchor: self.trailingAnchor)
self.backgroundColor = .white
}
static let identifier = "TaskListTableViewCell"
private let nameLabel: UILabel = {
let label = UILabel()
label.text = "Simulator user has requested new graphics quality"
label.numberOfLines = 0
return label
}()
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
After doing so, when I swipe the cell, the deleteAction overlaps with the content of the cell.
As you see in the screenshot, the cell's content overlaps with the deleteAction text.
Update
setConstraints sets views's translatesAutoresizingMaskIntoConstraints to false
You must add nameLabel to contentView.
Change
self.addSubview(nameLabel)
nameLabel.setConstraints(topAnchor: self.topAnchor,
leadingAnchor: self.leadingAnchor,
bottomAnchor: self.bottomAnchor,
trailingAnchor: self.trailingAnchor)
to
self.contentView.addSubview(nameLabel)
nameLabel.setConstraints(topAnchor: self.contentView.topAnchor,
leadingAnchor: self.contentView.leadingAnchor,
bottomAnchor: self.contentView.bottomAnchor,
trailingAnchor: self.contentView.trailingAnchor)
Result:

Cannot add collection view to two view controllers

I am have added collection view to two of my view controllers and when I click on the cell in the first view controller (TabBar.swift) it should go to the second view controller and vice Versa, but for some reason, the app crashes when I launch.
Here is the code for the first view controller: TabBar.swift
struct OpenViewController {
var viewController: UIViewController
}
class TabBar: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
addCollectionViewConstraints()
}
var viewControllerList = [
OpenViewController(viewController: FirstScreen())
]
// Setup the collection veiw
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellID")
cv.translatesAutoresizingMaskIntoConstraints = false
return cv
}()
// Add constraints to the collection view
func addCollectionViewConstraints() {
view.addSubview(collectionView)
collectionView.backgroundColor = .blue
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
collectionView.heightAnchor.constraint(equalTo: collectionView.widthAnchor, multiplier: 0.3).isActive = true
collectionView.delegate = self
collectionView.dataSource = self
}
}
Here is the code for the second view controller:
FirstScreen.swift
struct OpenViewControllerTwo {
var viewController: UIViewController
}
class FirstScreen: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
addCollectionViewConstraints()
}
var viewControllerList = [
OpenViewControllerTwo(viewController: FirstScreen())
]
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellID")
cv.translatesAutoresizingMaskIntoConstraints = false
return cv
}()
// Add constraints to the collection view
func addCollectionViewConstraints() {
view.addSubview(collectionView)
collectionView.backgroundColor = .blue
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
collectionView.heightAnchor.constraint(equalTo: collectionView.widthAnchor, multiplier: 0.3).isActive = true
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension FirstScreen: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
// The number of elements inside the collection view
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
// Adding the cells
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath)
// Customize the cells
cell.backgroundColor = .black
cell.layer.cornerRadius = collectionView.contentSize.height / 2
cell.layer.borderWidth = 1
cell.layer.borderColor = UIColor.black.cgColor
return cell
}
// The witdth and the height of the cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.height, height: collectionView.frame.height)
}
// Padding to the cells
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8)
}
// Selecting a cell and navigating to another view controller
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let openViewController = self.viewControllerList[indexPath.row]
self.present(openViewController.viewController, animated: false)
}
}
Crash log:
Your are getting memory issue because of viewControllerList is initialised in loops.
Just declare variable like this
var viewControllerList = [OpenViewController]()
then assign value like this in viewDidLoad.
viewControllerList = [
OpenViewController(viewController: FirstScreen())
]
I found that code in FirstScreen
var viewControllerList = [
OpenViewControllerTwo(viewController: FirstScreen())
]
When FirstScreen init, viewControllerList will init all call FirstScreen.
It created recursive recursive. Please change above code, put another class, ex: In FirstClass
var viewControllerList = [
OpenViewControllerTwo(viewController: SecondClass())
]

Data functions for UICollectionView not being called

Basically, I have a UICollectionView within a UIView (that extends the collection view data and delegate protocols). Certain UICollectionView functions, such as numberofSections and numberOfItemsInSection are being called, while others such as cellForRowAt are not being called.
The collection view in question is rolesCollectionView, and its data is the roles array. I have added some print statements to see which functions are being called, and only the aforementioned ones are. I'm also certain that this isn't an issue with the RolesCollectionViewCell, whose code I can also provide if necessary.
class ProjectSearchViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
var rolesCollectionView: UICollectionView!
var roles = ["Developer", "Designer", "Backend Developer", "Frontend Developer"]
override func viewDidLoad() {
super.viewDidLoad()
print("test")
// Do any additional setup after loading the view.
navigationItem.title = "Search Projects"
view.backgroundColor = .white
var rolesLayout = UICollectionViewFlowLayout()
rolesLayout.scrollDirection = .horizontal
rolesLayout.minimumLineSpacing = 8
rolesLayout.minimumInteritemSpacing = 8
rolesLayout.sectionInset = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8)
rolesLayout.estimatedItemSize = CGSize(width: 50, height: 25)
rolesCollectionView = UICollectionView(frame: .zero, collectionViewLayout: rolesLayout)
rolesCollectionView.backgroundColor = .white
rolesCollectionView.delegate = self
rolesCollectionView.dataSource = self
rolesCollectionView.register(RolesCollectionViewCell.self, forCellWithReuseIdentifier: "role")
rolesCollectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(rolesCollectionView)
rolesCollectionView.reloadData()
let newView = UIView()
newView.backgroundColor = .black
newView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(newView)
NSLayoutConstraint.activate([
newView.widthAnchor.constraint(equalToConstant: 50),
newView.heightAnchor.constraint(equalToConstant: 50),
newView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
newView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
setupConstraints()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// if collectionView == self.rolesCollectionView {
print("return")
print(roles.count)
return roles.count
// } else {
// return 0
// }
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
print("section")
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
print("cell for item at")
if collectionView == self.rolesCollectionView {
var cell = rolesCollectionView.dequeueReusableCell(withReuseIdentifier: "role", for: indexPath) as! RolesCollectionViewCell
cell.configure(roleName: roles[indexPath.row])
print(roles[indexPath.row])
return cell
} else {
return UICollectionViewCell()
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
//if collectionView == self.rolesCollectionView {
print("size")
print("test: \(collectionView == rolesCollectionView)")
return CGSize(width: 15.0, height: 15.0)
// }
}
func setupConstraints() {
NSLayoutConstraint.activate([
rolesCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8),
rolesCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8),
rolesCollectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8)
//rolesCollectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bot)
])
}
}

Nest a UICollectionView inside a UIVIew programmatically

I am attempting to get a UICollectionView to be inside a UIView as the framework I'm using requires a UIView to be returned. I have looked at this question: How do I add a UICollectionView to a UIView as a subview? and Adding UICollectionView inside UIView without Storyboards but not sure how to get it to work.
I have a attempted it like this:
class TopView : UIView, UICollectionViewDataSource, UICollectionViewDelegate {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .red
addSubview(collectionView)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
lazy var collectionView : UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.delegate = self
cv.dataSource = self
cv.register(HeaderCell.self, forCellWithReuseIdentifier: "HeaderCell")
cv.backgroundColor = .yellow
return cv
}()
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HeaderCell", for: indexPath) as! HeaderCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.collectionView.frame.width, height: 200)
}
func collectionView(_ collectionView: UICollectionView, numberOfSections section: Int) -> Int {
return 1
}
}
But I'm getting a blank screen.
Update:
This is how I add the TopView to a UIViewController:
class MainViewController: UIViewController {
var mainView = TopView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(mainView)
}
}
I get just a black screen.
TopView.swift
class TopView : UIView, UICollectionViewDataSource, UICollectionViewDelegate {
lazy var collectionView : UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
//If you set it false, you have to add constraints.
cv.translatesAutoresizingMaskIntoConstraints = false
cv.delegate = self
cv.dataSource = self
cv.register(HeaderCell.self, forCellWithReuseIdentifier: "HeaderCell")
cv.backgroundColor = .yellow
return cv
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .red
addSubview(collectionView)
//Add constraint
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func collectionView(_ collectionView: UICollectionView, numberOfSections section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 30
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HeaderCell", for: indexPath) as! HeaderCell
cell.backgroundColor = .cyan
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.collectionView.frame.size.width, height: 200)
}
}
ViewController.swift
lazy var topView: TopView = {
let tv = TopView()
tv.translatesAutoresizingMaskIntoConstraints = false
return tv
}()
func addTopView() {
view.addSubview(topView)
topView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
topView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
topView.topAnchor.constraint(equalTo: view.topAnchor, constant: 300).isActive = true
topView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
topView.heightAnchor.constraint(equalToConstant: 200).isActive = true
}
Call addTopView() from viewDidLoad()

Resources