UICollectionView is showing but the cells are not showing in swift - ios

I created a collectionView programmatically (without storyboard). I set the background color to red, and it is showing properly. But the cells are not showing. Does anyone know why the cells are not showing?
private let cellId = "cellId"
class InfoViewShow: NSObject, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
private let cellHeight:CGFloat = 80
var collectionView: UICollectionView?
let layout = UICollectionViewFlowLayout()
override init() {
super.init()
setupCollectionview()
collectionView?.registerClass(InfoCell.self, forCellWithReuseIdentifier: cellId)
}
private func setupCollectionview() {
if let view = UIApplication.sharedApplication().keyWindow {
//let y = (view.frame.width * 10 / 16) + 34 + 26
collectionView = UICollectionView(frame: .zero , collectionViewLayout: layout)
collectionView?.backgroundColor = UIColor.redColor()
collectionView?.delegate = self
collectionView?.dataSource = self
collectionView?.frame = CGRectMake(0, 0, view.frame.width, view.frame.height) // y to y
}
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellId, forIndexPath: indexPath)
cell.backgroundColor = UIColor.blackColor()
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(collectionView.frame.width, cellHeight)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(5, 5, 5, 5); //top,left,bottom,right
}
}

I dont' see you add collectionView to view.
if let view = UIApplication.sharedApplication().keyWindow {
//let y = (view.frame.width * 10 / 16) + 34 + 26
collectionView = UICollectionView(frame: .zero , collectionViewLayout: layout)
collectionView?.backgroundColor = UIColor.redColor()
collectionView?.delegate = self
collectionView?.dataSource = self
collectionView?.frame = CGRectMake(0, 0, view.frame.width, view.frame.height) // y to y
///try add
self.view.addSubview(collectionView)
}

You must implement numberOfSectionsInCollectionView of UICollectionViewDataSource delegate method.
This method is optional but you must implement it and return at least one section.

I know I am 6 years late to answer this question but I also struggled with it for 2 days before finding the mistake I was making. Hope this answer helps someone.
Check whether you have written the following two lines in your override func viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
self.collectionView.reloadData()

Related

iPhone X Collection View Cell glitch

I have a collection view which cells are 1/2 of screen width. The problem is that ONLY on iPhone X and Xs I have a line, that shows content beneath collection view. Why can it be so ?
import UIKit
import SnapKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(UICollectionViewCell.self), for: indexPath)
cell.backgroundColor = .white
return cell
}
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: NSStringFromClass(UICollectionViewCell.self))
layout.itemSize = CGSize(width: (UIScreen.main.bounds.width / 2), height: UIScreen.main.bounds.width / 2)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
if #available(iOS 11.0, *) {
collectionView.contentInsetAdjustmentBehavior = .always
}
collectionView.snp.makeConstraints({ make in
make.edges.equalTo(self.view)
})
}
}

Show only 7 uicollectionview cells

I have a UIcollectionview that allows scrolling the content horizontally only. Each UIcollectionviewCell is a custom view showing two labels one below the other. I have set constraints in the custom cell to position these labels. Irrespective of the screen width, I always want to show 7 UICollection cells. Is this possible?
You need to change itemSize by calculating from device width
let itemSpacing: CGFloat = 5
let itemsInOneLine: CGFloat = 7
let flow = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
flow.sectionInset = UIEdgeInsets(top: itemSpacing, left: itemSpacing, bottom: itemSpacing, right: itemSpacing)
flow.minimumInteritemSpacing = itemSpacing
flow.minimumLineSpacing = itemSpacing
let cellWidth = (UIScreen.main.bounds.width - (itemSpacing * 2) - ((itemsInOneLine - 1) * itemSpacing)) / itemsInOneLine
flow.itemSize = CGSize(width: cellWidth, height: 120)
Hope this is What you want,
Here is the code for this.
//
// ViewController.swift
// AssignmentSO
//
// Created by Anuradh Caldera on 4/24/19.
// Copyright © 2019 personal. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
private var mycollectionview: UICollectionView!
private let cellidentifier = "cellIdentifier"
private let minimuminterspace: CGFloat = 2
override func viewDidLoad() {
super.viewDidLoad()
setCollectionView()
}
}
extension ViewController {
fileprivate func setCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = minimuminterspace
layout.minimumInteritemSpacing = minimuminterspace
mycollectionview = UICollectionView(frame: .zero, collectionViewLayout: layout)
mycollectionview.translatesAutoresizingMaskIntoConstraints = false
mycollectionview.register(MyCell.self, forCellWithReuseIdentifier: cellidentifier)
mycollectionview.dataSource = self
mycollectionview.delegate = self
mycollectionview.backgroundColor = .white
mycollectionview.isPagingEnabled = true
// mycollectionview.contentInset = UIEdgeInsets(top: 0, left: minimuminterspace, bottom: 0, right: minimuminterspace)
view.addSubview(mycollectionview)
let collectionviewConstraints = [mycollectionview.leftAnchor.constraint(equalTo: view.leftAnchor, constant: minimuminterspace),
mycollectionview.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
mycollectionview.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -minimuminterspace),
mycollectionview.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height/4)]
NSLayoutConstraint.activate(collectionviewConstraints)
}
}
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellidentifier, for: indexPath) as! MyCell
cell.index = indexPath.item
cell.backgroundColor = .purple
return cell
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellwidth = mycollectionview.frame.width/7 - minimuminterspace
let cellheight = mycollectionview.frame.height
return CGSize(width: cellwidth, height: cellheight)
}
}
class MyCell: UICollectionViewCell {
private var mainlabel: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
setLabel()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var index: Int! {
didSet {
mainlabel.text = "\(index+1)"
}
}
}
extension MyCell {
fileprivate func setLabel() {
mainlabel = UILabel()
mainlabel.translatesAutoresizingMaskIntoConstraints = false
mainlabel.textColor = .white
mainlabel.textAlignment = .center
addSubview(mainlabel)
let mainlabelConstraints = [mainlabel.centerXAnchor.constraint(equalTo: centerXAnchor),
mainlabel.centerYAnchor.constraint(equalTo: centerYAnchor)]
NSLayoutConstraint.activate(mainlabelConstraints)
}
}
Note: if you want to show 7 cells, then it is better to enable pagination. you can change the height as your need. hope this will help to someone. cheers!
Step 1 - Implement UICollectionViewDelegateFlowLayout delegate
Step 2 - Add below method
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (collectionViewSize/7) , height: 50 )
}
Step 3 - pass size according to your requirement
Implement the collectionView layout delegate.
And divide the screen width in 7 parts as below.
please note following code is with respect to the collectionView width, considering the auto layout of collectionView width is set to screen margin.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.width/7, height:collectionView.bounds.height)
}
Though this will suffice your need, you will also need to handle the Cell's subviews to fit in the cell and display the content properly.

UICollectionView cell spacing not working anymore

I have been working on this app for a few days, I am working on laying out a UICollectionView to appear like a grid with no spacing in between the cells. It was working fantastically after I found this answer and implemented it into my own program. I worked on some other files and updated my computer, then I came back and tested this app just to see where I was and for some reason there is horizontal spacing in between cells. I have looked at a few other questions similar to this one, but I'm just wondering how to fix this and why this happened when I didn't change anything related to the layout.
Here's is what it looks like now:
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
var model = BoardModel()
var board = Board()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
collectionView.delegate = self
collectionView.dataSource = self
board = model.newGame(4, 4)
// Remove the spacing between the cells in collectionView
// Also make the cells the correct size to form a square/rectangle
let screenSize: CGRect! = collectionView.bounds
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: screenSize.width/CGFloat(board.columns), height: screenSize.width/CGFloat(board.columns))
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
collectionView!.collectionViewLayout = layout
// Center the collectionView
collectionView.contentInset.top = max((collectionView.frame.height - collectionView.contentSize.height) / 5, 0)
}
The reason I'm using the collectionView bounds instead of the UIScreen.mainScreen().bounds is because my collectionView has 20 spacing around all the edges.
Can you try
let width = UIScreen.main.bounds.width - 40 // convert it if it's not swift 4
let height = UIScreen.main.bounds.height - 40
//
or implement
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize.init(width: , height: )
}
import UIKit
class ViewController: UIViewController {
fileprivate let sectionInsets = UIEdgeInsets(top: 5.0, left: 5.0, bottom: 5.0, right: 5.0)
fileprivate let itemsPerRow: CGFloat = 2
override func viewDidLoad() {
super.viewDidLoad()
}
}
// MARK: UICollectionViewDelegateFlowLayout
extension ViewController : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{
let paddingSpace = sectionInsets.left * (itemsPerRow + 1)
let availableWidth = view.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
let heightPerItem = widthPerItem + 21
return CGSize(width: widthPerItem, height: heightPerItem)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets{
return sectionInsets
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat{
return sectionInsets.left
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat{
return 0
}
}

Add CollectionView as Table View Header

I want to show banner like this:
My approach is adding a CollectionView as a TableViewHeader
My code:
extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func configureHeaderView() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
let headerView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: headerHeight), collectionViewLayout: layout)
headerView.backgroundColor = .blue
headerView.isPagingEnabled = true
headerView.isUserInteractionEnabled = true
headerView.dataSource = self
headerView.delegate = self
headerView.register(BannerCollectionViewCell.self, forCellWithReuseIdentifier: BannerCollectionViewCell.reuseIdentifier)
headerView.showsHorizontalScrollIndicator = false
tableView.tableHeaderView = headerView
}
// MARK: UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BannerCollectionViewCell.reuseIdentifier, for: indexPath) as! BannerCollectionViewCell
return cell
}
// MARK: UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: headerHeight)
}
}
My BannerCollectionViewCell has a default image.
class BannerCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var bannerImageView: UIImageView!
}
But I don't see that image on my header. It just show an empty header.
you use the NIB, so you should use func register(UINib?, forCellWithReuseIdentifier: String) instead of func register(AnyClass?, forCellWithReuseIdentifier: String)
Maybe you're looking for an image pager like KIImagePager on the top instead of a collection view. You can also create the same using inbuilt PageViewController.
You can add a TableView separately below this.

UICollectionView vertical flow layout keep in collection bounds

I have a UICollectionView with vertical cells alignment, but I want also vertical section alignment, I also want to keep the sections inside the current frame of the UICollectionView, that means if a section reach the end and it's longer then the collection itself, then it will go to next line.
This is how it looks right now:
This is the final result I want to end up with:
This is my code so far:
class LettersCollectionTestViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionContainer: UIView!
var collectionView: UICollectionView?
private let ReuseIdentifierCollectionLetterCell = "LetterCollectionViewCell"
var collectionWords: NSArray?
var itemSize: CGFloat = 25.0
var itemSpacing: CGFloat = 5.0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let logoWord: String = "This is just this"
self.collectionWords = logoWord.componentsSeparatedByString(" ")
self.initializeCollection()
}
func initializeCollection() {
let collectionViewLayout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
collectionViewLayout.itemSize = CGSizeMake(self.itemSize, self.itemSize)
collectionViewLayout.minimumInteritemSpacing = 0
collectionViewLayout.minimumLineSpacing = self.itemSpacing
collectionViewLayout.scrollDirection = UICollectionViewScrollDirection.Vertical
let collectionView: UICollectionView = UICollectionView(frame: self.collectionContainer.bounds, collectionViewLayout: collectionViewLayout)
collectionView.delegate = self;
collectionView.dataSource = self;
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
collectionView.registerClass(LetterCollectionViewCell.self, forCellWithReuseIdentifier: self.ReuseIdentifierCollectionLetterCell)
collectionView.registerNib(UINib(nibName: self.ReuseIdentifierCollectionLetterCell, bundle: nil), forCellWithReuseIdentifier: self.ReuseIdentifierCollectionLetterCell)
self.collectionView = collectionView
self.collectionContainer.addSubview(collectionView)
}
// MARK: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("clicked item at index: \(indexPath.row)")
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: LetterCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(self.ReuseIdentifierCollectionLetterCell, forIndexPath: indexPath) as! LetterCollectionViewCell
let scalingTransform: CGAffineTransform = CGAffineTransformMakeScale(-1, 1)
cell.transform = scalingTransform
return cell
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (self.collectionWords?.objectAtIndex(section).length)!
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return (self.collectionWords?.count)!
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: self.itemSpacing, left: self.itemSpacing, bottom: self.itemSpacing, right: self.itemSpacing)
}
}
What do I need to do? I know I should create a custom FlowLayout, but where should I start? I never did it before.
Thanks in advance!

Resources