Swift UICollectionView in a UITableViewCell dynamic layout can't change cell height - uitableview

In Xcode 8.2.1 and Swift 3 I have a UICollectionView inside a UITableViewCell but I can't get the layout right. basically I want to be able to see all of the star. I can adjust the size of the star but I want to fix the underlying problem, expanding the blue band.
Here is a shot of the view The red band is contentView and the blue band is collectionView. At first glance it looks like collectionView height is the problem but it is actually being hidden by something else. I can't find or change whatever it is hiding the collectionView cell.
I am not using the storyboard beyond a view controller embedded in a navigator.
Here's all the relevant code.
class WishListsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView = UITableView()
let tableCellId = "WishListsCell"
let collectionCellId = "WishListsCollectionViewCell"
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = .white
tableView.register(WishListsCell.self, forCellReuseIdentifier: tableCellId)
self.view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
}
func numberOfSections(in tableView: UITableView) -> Int {
return wishLists.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: tableCellId, for: indexPath) as! WishListsCell
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView,willDisplay cell: UITableViewCell,forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? WishListsCell else { return }
//here setting the uitableview cell contains collectionview delgate conform to viewcontroller
tableViewCell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forSection: indexPath.section)
tableViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
}
func tableView(_ tableView: UITableView,didEndDisplaying cell: UITableViewCell,forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? WishListsCell else { return }
storedOffsets[indexPath.row] = tableViewCell.collectionViewOffset
}
}
extension WishListsViewController: UICollectionViewDelegate , UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionCellId, for: indexPath) as! WishListsCollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 100, height: 100)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
}
class WishListsCell: UITableViewCell {
private var collectionView: UICollectionView!
let cellId = "WishListsCollectionViewCell"
var collectionViewOffset: CGFloat {
get { return collectionView.contentOffset.x }
set { collectionView.contentOffset.x = newValue }
}
func setCollectionViewDataSourceDelegate<D: protocol<UICollectionViewDataSource, UICollectionViewDelegate>>
(dataSourceDelegate: D, forSection section : Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.tag = section
collectionView.reloadData()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
collectionView = UICollectionView(frame: contentView.frame, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .blue
collectionView.register(WishListsCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
contentView.backgroundColor = .red
self.contentView.addSubview(collectionView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class WishListsCollectionViewCell: UICollectionViewCell {
var imageView: UIImageView
override init(frame: CGRect) {
imageView = UIImageView()
super.init(frame: frame)
contentView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
contentView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .white
NSLayoutConstraint.activate([
NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal,
toItem: contentView, attribute: .width,
multiplier: 1.0, constant: 0.0),
NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal,
toItem: contentView, attribute: .height,
multiplier: 1.0, constant: 0.0),
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

You can Use View Debugging
Run the project, go back to Xcode and click on the Debug View Hierarchy button in the Debug bar. Alternatively, go to Debug\View Debugging\Capture View Hierarchy.
Now you can select your red view and Xcode will indicate which view is selected.
For more info. Check out: View Debugging in Xcode

Specifically, the problem was the collection view frame had not been properly set. This was only revealed by the great tip that I didn't know about in the accepted answer.
This fixed it:
self.collectionView.frame = CGRect(0, 0, screenWidth, (screenWidth / 4) * Constants.IMAGE_ASPECT_RATIO)

Related

UITableView didSelect issue with nested UiCollectionView

I have a tableView with cells that contain UiCollectionView. My didSelect tableView's delegate isn't called when I touch the cell on the collectionView.
I think it's my collectionView that get the touch instead. Do you have any elegant solution to keep the scroll enabled on my collectionView but disable the selection and pass it to the tableview ?
Here is my tableView declaration :
private lazy var tableView:UITableView = { [weak self] in
$0.register(TestTableViewCell.self, forCellReuseIdentifier: "identifier")
$0.delegate = self
$0.dataSource = self
return $0
}(UITableView())
Here are my delegate and dataSource methods:
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! TestTableViewCell
return cell
}
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
print(indexPath)
}
And here is my cell :
public class TestTableViewCell : UITableViewCell {
private lazy var collectionViewFlowLayout:UICollectionViewFlowLayout = {
$0.scrollDirection = .horizontal
$0.minimumLineSpacing = 0
$0.minimumInteritemSpacing = 0
return $0
}(UICollectionViewFlowLayout())
private lazy var collectionView:UICollectionView = {
$0.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "identifier")
$0.delegate = self
$0.dataSource = self
return $0
}(UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout))
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: cell:"identifier", for: indexPath) as! cell:UICollectionViewCell
return cell
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return collectionView.frame.size
}
}
If you spot any compilation error, excuse me, this is an anonymized copy/past. My app is running without error.
If you want an example of what I'm trying to do you can check AirBnb's app. TableView with some houses with cells and inside, pictures collectionView. Il you touch the collectionView, the tableView select the cell...
Thanks
I don't believe there is a "direct" way to do what you're asking. The collection view will respond to the gestures, so they can't "flow through" to the table view / cells without using a closure or protocol/delegate pattern.
Here's one approach...
We subclass UICollectionView and, on touchesBegan call a closure to tell the table view to select the row.
We can also implement scrollViewWillBeginDragging to select the row on collection view scroll, in addition to collection view "tap."
So...
View Controller class
class TableColTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// number of items in the collection view for each row
let myData: [Int] = [
12, 15, 8, 21, 17, 14,
16, 10, 5, 13, 20, 19,
]
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
])
tableView.register(SomeTableCell.self, forCellReuseIdentifier: "someTableCell")
tableView.dataSource = self
tableView.delegate = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "someTableCell", for: indexPath) as! SomeTableCell
cell.rowTitleLabel.text = "Row \(indexPath.row)"
cell.numItems = myData[indexPath.row]
// closure for the cell to tell us to select it
// because its collection view was tapped
cell.passThroughSelect = { [weak self] theCell in
guard let self = self,
let pth = self.tableView.indexPath(for: theCell)
else { return }
self.tableView.selectRow(at: pth, animated: true, scrollPosition: .none)
// selecting a row programmatically does NOT trigger didSelectRowAt
// so we'll call our own did select func
self.myDidSelect(pth)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// pass this on to our own did select func
// so it matches what happens when programmatically selecting the row
myDidSelect(indexPath)
}
func myDidSelect(_ indexPath: IndexPath) {
print("Table View - didSelectRowAt", indexPath)
// do something because the row was selected
}
}
Table View Cell class
class SomeTableCell: UITableViewCell {
// callback closure
var passThroughSelect: ((UITableViewCell) -> ())?
var rowTitleLabel = UILabel()
var collectionView: SubCollectionView!
var numItems: Int = 0 {
didSet {
collectionView.reloadData()
}
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
let fl = UICollectionViewFlowLayout()
fl.scrollDirection = .horizontal
fl.estimatedItemSize = CGSize(width: 120.0, height: 52.0)
fl.minimumLineSpacing = 12
fl.minimumInteritemSpacing = 12
collectionView = SubCollectionView(frame: .zero, collectionViewLayout: fl)
rowTitleLabel.translatesAutoresizingMaskIntoConstraints = false
collectionView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(rowTitleLabel)
contentView.addSubview(collectionView)
let g = contentView.layoutMarginsGuide
// avoid auto-layout complaints
let c = collectionView.heightAnchor.constraint(equalToConstant: 60.0)
c.priority = .required - 1
NSLayoutConstraint.activate([
rowTitleLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
rowTitleLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
rowTitleLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
rowTitleLabel.heightAnchor.constraint(equalToConstant: 30.0),
collectionView.topAnchor.constraint(equalTo: rowTitleLabel.bottomAnchor, constant: 4.0),
collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
collectionView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
c,
])
collectionView.register(SomeCollectionCell.self, forCellWithReuseIdentifier: "someCollectionCell")
collectionView.dataSource = self
collectionView.delegate = self
collectionView.passThroughTouch = { [weak self] in
guard let self = self else { return }
self.passThroughSelect?(self)
}
collectionView.backgroundColor = .systemYellow
}
}
extension SomeTableCell: UICollectionViewDataSource, UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numItems
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "someCollectionCell", for: indexPath) as! SomeCollectionCell
cell.label.text = "Cell \(indexPath.item)"
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Collection View - didSelectItemAt", indexPath)
}
}
extension SomeTableCell: UIScrollViewDelegate {
// if you only want the table cell selected on TAP, don't implement this
// if you want the table cell selected on CollectionView SCROLL, implement this
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.passThroughSelect?(self)
}
}
UICollectionView subclass
class SubCollectionView: UICollectionView {
var passThroughTouch: (() -> ())?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// this allows the collection view cell to be selected
super.touchesBegan(touches, with: event)
// this tells the controller (the table view cell)
// that the collection view was tapped
passThroughTouch?()
}
}
UICollectionView Cell class
class SomeCollectionCell: UICollectionViewCell {
var label = UILabel()
var styleView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
styleView.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
styleView.addSubview(label)
contentView.addSubview(styleView)
let g = contentView
NSLayoutConstraint.activate([
styleView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
styleView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
styleView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
styleView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
label.topAnchor.constraint(equalTo: styleView.topAnchor, constant: 8.0),
label.leadingAnchor.constraint(equalTo: styleView.leadingAnchor, constant: 8.0),
label.trailingAnchor.constraint(equalTo: styleView.trailingAnchor, constant: -8.0),
label.bottomAnchor.constraint(equalTo: styleView.bottomAnchor, constant: -8.0),
])
label.textColor = .white
styleView.backgroundColor = UIColor(white: 0.5, alpha: 1.0)
styleView.layer.borderColor = UIColor.white.cgColor
styleView.layer.borderWidth = 1
styleView.layer.cornerRadius = 6
}
override var isSelected: Bool {
didSet {
label.textColor = isSelected ? .red : .white
styleView.backgroundColor = isSelected ? UIColor(white: 0.95, alpha: 1.0) : UIColor(white: 0.5, alpha: 1.0)
styleView.layer.borderColor = isSelected ? UIColor.red.cgColor : UIColor.white.cgColor
}
}
}
You can do the following
First in first, print something in didSelectItem of your collectionView delegate, to make ensure that your collectionView cell is tapped.
add a delegate property in your UICollectionViewClass and call the delegate in the DidSelectItem if the step 1 is performing correctly.
In your UITableViewController, you have a function cellForRowAtIndexPath, here add the delegate property for the associate cell.
If you can print something in your delegate function, then you are at your last step. Call super.didSelect..with your indexPath, because now you have everything to call didSelect manually.
Maybe you would like to try allowsSelection property of UICollectionView. If you set this property false, your collection view cells are not selected any more.
And I think tableView didSelect can capture user interaction. If UITableView still can not capture didSelect, you can give delegate to collectionView and fire it once it's tapped by adding a tap gesture onto UICollectionView.

Swift UICollectionView inside UITableViewCell Programmatically

Greeting folks,
I'm trying to add UICollectionView inside UITableViewCell Programmatically , however the collectionView is not called ever. I went through the code several times with no luck. I looked around to find out also with no luck. I went through Youtube tutorials I found them do the same.
would you help please ☚ī¸
class adsTableViewCell: UITableViewCell {
var adsImages: [UIImage]? {
didSet{
collectionView.reloadData()
}
}
let cellID = "Celled"
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 10
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.backgroundColor = UIColor.red
return cv
}()
override func awakeFromNib() {
super.awakeFromNib()
self.collectionView.delegate = self
self.collectionView.dataSource = self
collectionView.register(imageCell.self, forCellWithReuseIdentifier: cellID)
collectionView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
collectionView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
collectionView.showsHorizontalScrollIndicator = false
collectionView.isPagingEnabled = false
self.addSubview(collectionView)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension adsTableViewCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! imageCell
if let imageName = adsImages?[indexPath.item]{
cell.imageView.image = imageName
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 300, height: frame.height - 10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 14, bottom: 0, right: 14)
}
private class imageCell: UICollectionViewCell {
let imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.layer.cornerRadius = 10
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup(){
addSubview(imageView)
imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
}
This is the UITableView, cellForRowAt
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "addViewCell", for: indexPath) as! adsTableViewCell
cell.adsImages = images
cell.collectionView.reloadData()
cell.backgroundColor = UIColor.systemTeal
cell.selectionStyle = .none
return cell
}
I found the Solution
simply I had to change :
override func awakeFromNib() {
To
override required init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
and it is work fine now

UICollectionViewController footer not re-positioning itself properly after endEditing

I have a simple UICollectionViewController that is one section with a header and footer pinned to visible bounds. When I click a textField in the footer, the footer automatically animates above the keyboard and the collectionView scrolls to show the cells that otherwise would have been hidden by the keyboard as you would expect. However, when I click one outside of the keyboard, and dismiss it with a call to self.view.endEditing(true) the footer and collectionView do not react unless the collectionView is scrolled near the bottom. If the collectionView is scrolled near the bottom, the footer and collectionView animate as expected.
How can I force the footer and collectionView to animate properly every time?
In the images below, the header is orange, footer is green, and there are 10 cells that alternate red and blue.
Actual Behavior (occurs when you are not scrolled near the bottom of the collectionView when the keyboard dismisses)
Desired Behavior (occurs when you are scrolled at or near the bottom of the collectionView when the keyboard dismisses)
I know there are some methods to achieve this with Notifications when the keyboard appears and disappears but I would prefer to just use the default UICollectionViewController behavior if possible. Is there some configuration or setting I am missing?
Code:
New Single View App. Delete StoryBoard and ViewController.swift. Delete the main storyboard entry from the info plist file.
AppDelegate.swift
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = CollectionViewController.init()
return true
}
}
CollectionViewController.swift
import UIKit
private let reuseIdentifier = "Cell"
private let collectionViewHeaderFooterReuseIdentifier = "MyHeaderFooterClass"
class CollectionViewController: UICollectionViewController {
init() {
let collectionViewFlowLayout = UICollectionViewFlowLayout.init()
collectionViewFlowLayout.sectionHeadersPinToVisibleBounds = true
collectionViewFlowLayout.sectionFootersPinToVisibleBounds = true
super.init(collectionViewLayout: collectionViewFlowLayout)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
// Register cell classes
self.collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
self.collectionView?.register(MyHeaderFooterClass.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier)
self.collectionView?.register(MyHeaderFooterClass.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier)
self.collectionView?.backgroundColor = UIColor.white
self.collectionView?.dataSource = self
self.collectionView?.delegate = self
}
}
// MARK: UICollectionViewDelegate
extension CollectionViewController {
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
DispatchQueue.main.async {
self.view.endEditing(true)
self.collectionViewLayout.invalidateLayout()
self.collectionView?.layoutIfNeeded()
}
}
}
// MARK: - UICollectionViewDataSource
extension CollectionViewController {
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return 10
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
switch indexPath.row % 2 {
case 0:
cell.backgroundColor = UIColor.red
case 1:
cell.backgroundColor = UIColor.blue
default:
cell.backgroundColor = UIColor.gray
}
return cell
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier, for: indexPath)
if kind == UICollectionView.elementKindSectionHeader {
view.backgroundColor = UIColor.orange
}
else { //footer
view.backgroundColor = UIColor.green
}
return view
}
}
// MARK: - Collection View Flow Layout Delegate
extension CollectionViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 100)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 100)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 100)
}
}
MyHeaderFooterClass
import UIKit
class MyHeaderFooterClass: UICollectionReusableView {
let textField: UITextField = {
let view = UITextField.init()
view.placeholder = "enter text here"
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(textField)
self.setNeedsUpdateConstraints()
}
override func updateConstraints() {
textFieldConstraints()
super.updateConstraints()
}
private func textFieldConstraints() {
NSLayoutConstraint(item: textField, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: textField, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: textField, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: textField, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0.0).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
From documentation:
func layoutIfNeeded()
Use this method to force the view to update its layout immediately.
func invalidateLayout()
This method invalidates the layout of the collection view itself and
returns right away.
Solution:
Looking at your code, you are already updating collectionViewLayout. So, you don't need to force update collectionView again. Therefore, simply removing self.collectionView?.layoutIfNeeded() alone will solve your issue.
Change your code as below:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
DispatchQueue.main.async {
self.view.endEditing(true)
self.collectionViewLayout.invalidateLayout()
//self.collectionView?.layoutIfNeeded()
}
}

How to properly add an UICollectionView inside UITableViewCell using IOS 12

For some reasons I cannot properly display some items from a collection inside an tableview cell when using Xcode 10 beta. I tried all I know for the last 4 days.
I made a small project sample to see what my issue is.
Full code is here if someone wants to run it locally: https://github.com/adrianstanciu24/CollectionViewInsideUITableViewCell
I first add an table view with 2 different resizable cells, first cell has the collection view and a label:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.estimatedRowHeight = 44
tableView.rowHeight = UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "collCell") as! CollectionTableViewCell
cell.collectionView.collectionViewLayout.invalidateLayout()
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "normalCell")!
return cell
}
}
}
Here is the cell with collection view defined. This also has a height constraint which I updated in layoutSubviews:
class CollectionTableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
}
override func layoutSubviews() {
super.layoutSubviews()
collectionViewHeightConstraint.constant = collectionView.collectionViewLayout.collectionViewContentSize.height
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "taskCell", for: indexPath as IndexPath) as! TaskCollectionViewCell
cell.name.text = "Task_" + String(indexPath.row)
return cell
}
}
Below is a screenshot with the collection view constraint and how the storyboard looks:
And this is how it looks when running:
The cells are squashed and label on top disappears. What I want is the collection view should grow to show all elements and also making table view cell to resize, but that is not happening at the moment and I can't figure out where the issue is.
If you want the following output:
Code
ViewController:
class ViewController: UIViewController {
let list = [String](repeating: "Label", count: 10)
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
tableView.reloadData()
}
public lazy var tableView: UITableView = { [unowned self] in
let v = UITableView.init(frame: .zero)
v.delegate = self
v.dataSource = self
v.estimatedRowHeight = 44
v.rowHeight = UITableViewAutomaticDimension
v.register(TableCell.self, forCellReuseIdentifier: "TableCell")
return v
}()
}
extension ViewController: UITableViewDelegate{
}
extension ViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as! TableCell
cell.label.text = "\(list[indexPath.row]) \(indexPath.row)"
return cell
}
}
TableCell:
class TableCell: UITableViewCell{
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
func commonInit(){
contentView.addSubview(label)
contentView.addSubview(collectionView)
updateConstraints()
}
override func updateConstraints() {
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: topAnchor),
label.leadingAnchor.constraint(equalTo: leadingAnchor),
label.trailingAnchor.constraint(equalTo: trailingAnchor)
])
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: label.bottomAnchor),
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor),
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor),
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor),
])
super.updateConstraints()
}
let list = [String](repeating: "Task_", count: 10)
public let label: UILabel = {
let v = UILabel()
v.textAlignment = .center
return v
}()
public lazy var collectionView: UICollectionView = { [unowned self] in
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
let v = UICollectionView(frame: .zero, collectionViewLayout: layout)
v.register(CollectionCell.self, forCellWithReuseIdentifier: "CollectionCell")
v.delegate = self
v.dataSource = self
v.isScrollEnabled = false
return v
}()
override func sizeThatFits(_ size: CGSize) -> CGSize {
let collectionCellHeight = 50
let rows = list.count / 5 // 5: items per row
let labelHeight = 20 // you can calculate String height
let height = CGFloat((collectionCellHeight * rows) + labelHeight)
let width = contentView.frame.size.width
return CGSize(width: width, height: height)
}
}
extension TableCell: UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return list.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
cell.label.text = "\(list[indexPath.item])\(indexPath.item)"
return cell
}
}
extension TableCell: UICollectionViewDelegate{
}
extension TableCell: UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width/5, height: 50)
}
}
CollectionCell
class CollectionCell: UICollectionViewCell{
let padding: CGFloat = 5
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit(){
backgroundColor = .yellow
contentView.addSubview(label)
updateConstraints()
}
override func updateConstraints() {
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: topAnchor, constant: padding),
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding),
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding),
label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -padding)
])
super.updateConstraints()
}
public let label: UILabel = {
let v = UILabel()
v.textColor = .darkText
v.minimumScaleFactor = 0.5
v.numberOfLines = 1
return v
}()
}
Made with Swift 5.3 and tested on iOS 14, the follow it should work just copy and paste 😉:
TableViewController.swift
import UIKit
import SnapKit
class TableViewController: UIViewController {
private let tableView: UITableView = UITableView()
private let tableViewCellId = "TableViewCell"
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
}
// MARK: - Setup UIs
extension TableViewController {
private func setupUI() {
tableView.delegate = self
tableView.dataSource = self
tableView.register(TableViewCell.self, forCellReuseIdentifier: tableViewCellId)
view.addSubview(tableView)
tableView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
}
}
// MARK: - Delegate & DataSource
extension TableViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCellId) as! TableViewCell
cell.backgroundColor = .white
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
TableViewCell.swift
import UIKit
import SnapKit
class TableViewCell: UITableViewCell {
private let list = [String](repeating: "Row ", count: 10)
private let collectionViewLayout = UICollectionViewFlowLayout()
lazy private var collectionView: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
override func layoutSubviews() {
setupUI()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
// MARK: - UI Setup
extension TableViewCell {
private func setupUI() {
// layout.minimumLineSpacing = 5
// layout.minimumInteritemSpacing = 5
collectionViewLayout.scrollDirection = .horizontal
collectionView.backgroundColor = .clear
collectionView.showsHorizontalScrollIndicator = false
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionCell")
collectionView.delegate = self
collectionView.dataSource = self
addSubview(collectionView)
collectionView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
}
}
extension TableViewCell: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return list.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionViewCell
cell.titleLabel.text = "\(list[indexPath.item])\(indexPath.item)"
return cell
}
}
extension TableViewCell: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width / 5, height: 100)
}
}
CollectionViewCell.swift
import UIKit
class CollectionViewCell: UICollectionViewCell {
var titleLabel: UILabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
setupUI()
}
}
// MARK: - UI Setup
extension CollectionViewCell {
private func setupUI() {
titleLabel.font = UIFont(name: "HelveticaNeue", size: 20)
titleLabel.textColor = .white
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.backgroundColor = .systemGreen
titleLabel.textAlignment = .center
addSubview(titleLabel)
titleLabel.snp.makeConstraints {
$0.centerX.centerY.equalToSuperview()
$0.height.equalTo(60)
$0.width.equalTo(150)
}
}
}
If your desired output is following
Then replace your code of collectionview with this
class CollectionTableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!
var arrForString:[String] = ["Task_0","Task_1","Task_3","Task_4","Task_5","Task_6","Task_7","Task_8","Task_9","Task_10"]
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrForString.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "taskCell", for: indexPath as IndexPath) as! TaskCollectionViewCell
cell.name.text = arrForString[indexPath.row]
cell.layoutIfNeeded()
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
//we are just measuring height so we add a padding constant to give the label some room to breathe!
var padding: CGFloat = 10.0
var height = 10.0
height = Double(estimateFrameForText(text: arrForString[indexPath.row]).height + padding)
return CGSize(width: 50, height: height)
}
private func estimateFrameForText(text: String) -> CGRect {
//we make the height arbitrarily large so we don't undershoot height in calculation
let height: CGFloat = 120
let size = CGSize(width: 50, height: height)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let attributes = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18, weight: UIFont.Weight.light)]
return NSString(string: text).boundingRect(with: size, options: options, attributes: attributes, context: nil)
}
}
feel free to ask.

Select collection view cell on load - Custom UICollectionView class

I have a custom collection view (tabBarCollectionView), which should load with the first cell being selected, as per the code below. However, this is not working. I know this as the cell should be a different colour when selected, but isn't.
override init(frame: CGRect) {
super.init(frame: frame)
tabBarCollectionView.register(TabBarCell.self, forCellWithReuseIdentifier: cellIdentifier)
addSubview(tabBarCollectionView)
tabBarCollectionView.translatesAutoresizingMaskIntoConstraints = false
addConstraintsWithFormat("H:|[v0]|", views: tabBarCollectionView)
addConstraintsWithFormat("V:|[v0]|", views: tabBarCollectionView)
tabBarCollectionView.selectItem(at: IndexPath(item: 0, section: 0), animated: false, scrollPosition: [])
}
Full code of custom UIView class is inserted below:
import Foundation
import UIKit
class TabBar: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let cellIdentifier = "Cell"
let imageNames = ["homeIcon", "exploreIcon", "addIcon", "inboxIcon", "profileIcon"]
lazy var tabBarCollectionView: UICollectionView = {
// All collection view implementations in here
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.backgroundColor = UIColor.clear
return collectionView
}()
override init(frame: CGRect) {
super.init(frame: frame)
tabBarCollectionView.register(TabBarCell.self, forCellWithReuseIdentifier: cellIdentifier)
addSubview(tabBarCollectionView)
tabBarCollectionView.translatesAutoresizingMaskIntoConstraints = false
addConstraintsWithFormat("H:|[v0]|", views: tabBarCollectionView)
addConstraintsWithFormat("V:|[v0]|", views: tabBarCollectionView)
self.tabBarCollectionView.allowsSelection = true
self.tabBarCollectionView.selectItem(at: IndexPath(item: 0, section: 0), animated: false, scrollPosition: [])
}
override func layoutSubviews() {
super.layoutSubviews()
tabBarCollectionView.allowsSelection = true
tabBarCollectionView.selectItem(at: IndexPath(item: 0, section: 0), animated: false, scrollPosition: [])
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! TabBarCell
cell.backgroundColor = UIColor.clear
cell.tabBarImageView.image = UIImage(named: imageNames[indexPath.item])?.withRenderingMode(.alwaysTemplate)
cell.tabBarImageView.tintColor = UIColor.pinpointGrey
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.width / 5, height: frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class TabBarCell: UICollectionViewCell {
let tabBarImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "homeIcon")?.withRenderingMode(.alwaysTemplate)
imageView.tintColor = UIColor.pinpointGrey
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
func setupViews() {
backgroundColor = UIColor.clear
addSubview(tabBarImageView)
addConstraintsWithFormat("H:[v0(42)]", views: tabBarImageView)
addConstraintsWithFormat("V:[v0(42)]", views: tabBarImageView)
addConstraint(NSLayoutConstraint(item: tabBarImageView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0))
addConstraint(NSLayoutConstraint(item: tabBarImageView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0))
}
override var isHighlighted: Bool {
didSet {
if tabBarImageView.isHighlighted == true {
self.tabBarImageView.tintColor = UIColor.pinpointBlue
} else {
self.tabBarImageView.tintColor = UIColor.pinpointGrey
}
}
}
override var isSelected: Bool {
didSet {
tabBarImageView.tintColor = isSelected ? UIColor.pinpointBlue : UIColor.pinpointGrey
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Where is your datasource set? Do you load it separately and then do a reloadData()?
If yes, then you should select the cell then and not during your viewDidLoad method as during load the collection view might not have been populated yet.
You could also add to a viewWillAppear/viewDidAppear method as this gets called after the collection view has been populated

Resources