CollectionView infinite scroll in Swift with Json parse - ios

I wrote the code for collectionView infinite scroll with json parse. Next want to view 20 data each time. After print 20data i will show footer.
Now it is going to view all data in a time. Json parse is ok, also footer view is ok. But the problem is infinite-scroll is not working at all.
Here is my all code:
import Foundation
import UIKit
enum LoadMoreStatus{
case loading
case finished
case haveMore
}
class Product: NSObject {
var id: Int?
var category_id: Int?
var image: String?
var name: String?
var ar_name: String?
var ar_description: String?
var price: NSNumber?
var quantity: String?
var is_featured: String?
var seller_id: String?
var payment_required: String?
var is_editors_choice: String?
var created_at: String?
var updated_at: String?
}
let categoryCellid = "categoryCellid"
class ProductByCategoryCollectionView: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var headercellId = "headercellId"
var footerCellid = "firstfootercellid"
var numberOfCells = 5
var loadingStatus = LoadMoreStatus.haveMore
var arrProduct = [Product]()
var category_id:Int = 0;
var product_count:Int = 0;
func reloadData(){
collectionView?.reloadData()
if numberOfCells > 0 {
collectionView?.scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: true)
}
}
func loadMore() {
if numberOfCells >= arrProduct.count{ // here will show untill 22
loadingStatus = .finished
collectionView?.reloadData()
return
}
Timer.schedule(delay: 2) { timer in
self.numberOfCells += 10
self.collectionView?.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.getPropductListByCategory()
collectionView?.backgroundColor = .white
navigationItem.title = "Product"
navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil)
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Sort By", style: .plain, target: nil, action: nil)
self.setupHeaderView()
collectionView?.register(ProductByCategoryCollectionViewCell.self, forCellWithReuseIdentifier: categoryCellid)
collectionView?.register(ProductByCategoryFooterCell.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: footerCellid)
}
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
var text=""
switch UIDevice.current.orientation{
case .portrait:
text="Portrait"
case .portraitUpsideDown:
text="PortraitUpsideDown"
case .landscapeLeft:
text="LandscapeLeft"
case .landscapeRight:
text="LandscapeRight"
default:
text="Another"
}
NSLog("You have moved: \(text)")
collectionView?.reloadData()
}
func showCategoryDetailSegue() {
let detailcontroller = UIViewController()
navigationController?.pushViewController(detailcontroller, animated: true)
}
func sortBtnTarget() {
}
func filterBtnTarget() {
}
let dividedLine: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0.4, alpha: 0.4)
return view
}()
let totalItemLabel: UILabel = {
let label = UILabel()
label.text = ""
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 15)
label.backgroundColor = UIColor.white
return label
}()
let dividerLineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.white
return view
}()
func setupHeaderView(){
view.backgroundColor = UIColor(white: 0.4, alpha: 0.4)
dividedLine.frame = CGRect(x: 0, y: 95, width: view.frame.width, height: 1)
totalItemLabel.frame = CGRect(x: 0, y: 55, width: view.frame.width, height: 40)
view.addSubview(totalItemLabel)
view.addSubview(dividedLine)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrProduct.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(indexPath.row==arrProduct.count-1){
if loadingStatus == .haveMore {
self.perform(#selector(ProductByCategoryCollectionView.loadMore), with: nil, afterDelay: 0)
}
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: categoryCellid, for: indexPath) as! ProductByCategoryCollectionViewCell
cell.callProductObject4Cell = arrProduct[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 172, height: 300)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(32, 10, 0, 10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let controller1 = UICollectionViewController(collectionViewLayout: layout)
navigationController?.pushViewController(controller1, animated: true)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
collectionView?.collectionViewLayout.invalidateLayout()
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var footerView:ProductByCategoryFooterCell!
if (kind == UICollectionElementKindSectionFooter) && (loadingStatus != .finished){
footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerCellid, for: indexPath) as! ProductByCategoryFooterCell
}
return footerView
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return (loadingStatus == .finished) ? CGSize.zero : CGSize(width: self.view.frame.width, height: 50)
}
}
class ProductByCategoryCollectionViewCell: UICollectionViewCell {
var callProductObject4Cell: Product?{
didSet {
productLabel.text = callProductObject4Cell?.name
if let price = callProductObject4Cell?.price {
//priceLabel.text = "$\(price)"
priceLabel.text = "\(price) TK"
} else {
priceLabel.text = ""
}
if let profileImageUrl = callProductObject4Cell?.image {
productImage.loadImageUsingUrlString(profileImageUrl)
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupcategoryCell()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let productImage: UIImageView = {
let image = UIImageView()
image.image = UIImage(named: "default")
image.contentMode = .scaleAspectFit
image.layer.borderWidth = 1
image.layer.borderColor = UIColor.orange.cgColor
image.layer.masksToBounds = true
return image
}()
let productLabel: UILabel = {
let label = UILabel()
label.text = "productName"
label.textColor = .black
label.numberOfLines = 0
label.font = UIFont.boldSystemFont(ofSize: 10)
return label
}()
let priceLabel: UILabel = {
let label = UILabel()
// label.backgroundColor = .lightGray
label.text = ""
label.textColor = .orange
label.font = UIFont.systemFont(ofSize: 13)
return label
}()
func setupcategoryCell() {
addSubview(productImage)
addSubview(productLabel)
addSubview(priceLabel)
addConstraintsWithFormat("H:|[v0]|", views: productImage)
addConstraintsWithFormat("V:|[v0(230)]-2-[v1][v2(10)]-5-|", views: productImage,productLabel, priceLabel)
addConstraintsWithFormat("H:|[v0]|", views: productLabel)
addConstraintsWithFormat("H:|[v0]|", views: priceLabel)
}
}
class ProductByCategoryFooterCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
setupCell()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let menuHeaderLabel: UILabel = {
let label = UILabel()
label.text = "loadin more waiting"
label.textColor = .green
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 15)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setupCell() {
addSubview(menuHeaderLabel)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": menuHeaderLabel]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-5-[v0(30)]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": menuHeaderLabel]))
}
}
extension Timer {
class func schedule(delay: TimeInterval, handler: #escaping (Timer!) -> Void) -> Timer {
let fireDate = delay + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, 0, 0, 0, handler)
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
return timer!
}
class func schedule(repeatInterval interval: TimeInterval, handler: #escaping (Timer!) -> Void) -> Timer {
let fireDate = interval + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, interval, 0, 0, handler)
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
return timer!
}
}

enum LoadMoreStatus {
case loading
case finished
case haveMore
}
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var verticalDataSource = [String]()
var firstCellid = "firstcellid"
var firstFooterCellid = "firstfootercellid"
var numberOfCells = 5
var loadingStatus = LoadMoreStatus.haveMore
func reloadData() {
//numberOfCells = 10
collectionView?.reloadData()
if numberOfCells > 0 {
collectionView?.scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: true)
}
}
func loadMore() {
if numberOfCells >= 40 {
// here will show untill finished number
loadingStatus = .finished
collectionView?.reloadData()
return
}
// Replace code with web service and append to data source
Timer.schedule(delay: 2) { timer in
self.numberOfCells += 2
self.collectionView?.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.automaticallyAdjustsScrollViewInsets = false
collectionView?.register(VerticalCollectionViewCell.self, forCellWithReuseIdentifier: firstCellid)
collectionView?.register(VerticalCollectionViewCell2.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: firstFooterCellid)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK - Rotation methods
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
var text=""
switch UIDevice.current.orientation {
case .portrait:
text="Portrait"
case .portraitUpsideDown:
text="PortraitUpsideDown"
case .landscapeLeft:
text="LandscapeLeft"
case .landscapeRight:
text="LandscapeRight"
default:
text="Another"
}
NSLog("You have moved: \(text)")
collectionView?.reloadData()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numberOfCells
}
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(indexPath.row==numberOfCells-1) {
if loadingStatus == .haveMore {
self.perform(#selector(ViewController.loadMore), with: nil, afterDelay: 0)
}
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: firstCellid, for: indexPath) as! VerticalCollectionViewCell
cell.menuHeaderLabel.text = "Labet text no \(indexPath.item)"
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.view.frame.width, height: 100)
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var footerView:VerticalCollectionViewCell2!
if (kind == UICollectionElementKindSectionFooter) && (loadingStatus != .finished) {
footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: firstFooterCellid, for: indexPath) as! VerticalCollectionViewCell2
}
return footerView
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return (loadingStatus == .finished) ? CGSize.zero : CGSize(width: self.view.frame.width, height: 50)
}
}
class VerticalCollectionViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupCell()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let menuHeaderLabel: UILabel = {
let label = UILabel()
label.text = "lable text"
label.textColor = .orange
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 15)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setupCell() {
addSubview(menuHeaderLabel)
// addTaskButton.addTarget(self, action: #selector(MenuHeader.addTask), for: .touchUpInside)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": menuHeaderLabel]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-5-[v0(30)]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": menuHeaderLabel]))
}
}

Related

Making animating horizontal indicator using collectionView

I'm working on App where I have to manage my horizontal indicator on CollectionviewCell, while scrolling CollectionView and by selecting any Cell.
This is what I’m looking for(Just focus on Horizontal CollectionView)
As I have implemented this But I’m not getting the exact functionality/behavior AND unable to stick horizontal indicator on collectionviewCell while scrolling. I can only stick if i make a horizontal indicator in CollectionViewCell But in this Case I’m unable to apply sliding animation.
This is what I have implemented
Here is my Code Snippet for MENUBAR
import UIKit
class MenuBar: UITableViewHeaderFooterView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UIScrollViewDelegate {
//MARK:- Properties
let cellId = "cellId"
let menuNames = ["Recommeded", "Popular", "Free", "Trending", "Love Songs", " Free Songs"]
var horizontalBarLeftAnchorConstraint : NSLayoutConstraint?
lazy var collectionView : UICollectionView = {
let cv = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
cv.translatesAutoresizingMaskIntoConstraints = false
cv.dataSource = self
cv.delegate = self
cv.showsHorizontalScrollIndicator = false
cv.backgroundColor = UIColor.clear
return cv
}()
let horizontalView : UIView = {
let v = UIView()
v.backgroundColor = UIColor.red
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
//MARK:- default methods
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
setupCollectionView()
setupHorizontalBar()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK:- Functions
private func setupCollectionView() {
if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.scrollDirection = .horizontal
}
addSubview(collectionView)
collectionView.register(MenuCell.self, forCellWithReuseIdentifier: cellId)
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true
}
private func setupHorizontalBar() {
addSubview(horizontalView)
let textSize = (menuNames[0] as NSString).size(withAttributes: nil)
let cellSize = textSize.width + 50
let indicatorLineWith = 25/2
let x = (cellSize/2) - CGFloat(indicatorLineWith)
//x,y,w,h
horizontalBarLeftAnchorConstraint =
horizontalView.leftAnchor.constraint(equalTo: leftAnchor, constant: x )
horizontalBarLeftAnchorConstraint?.isActive = true
horizontalView.heightAnchor.constraint(equalToConstant: 5).isActive = true
horizontalView.widthAnchor.constraint(equalToConstant: 25).isActive = true
horizontalView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
//MARK:- CollectionView methods
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return menuNames.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MenuCell
cell.menuName = menuNames[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let size = (menuNames[indexPath.row] as NSString).size(withAttributes: nil)
return CGSize(width: (size.width + 50), height: frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//getting Cell size on screen
let attributes : UICollectionViewLayoutAttributes = collectionView.layoutAttributesForItem(at: indexPath)!
let indicatorSize = 25/2
let cellRect = attributes.frame
let cellFrameInSuperView = collectionView.convert(cellRect, to: collectionView)
let textSize = (menuNames[indexPath.row] as NSString).size(withAttributes: nil)
let cellSize = textSize.width + 50
let x = (CGFloat(cellFrameInSuperView.origin.x) + (cellSize/2)) - CGFloat(indicatorSize)
horizontalBarLeftAnchorConstraint?.constant = x
UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
self.layoutIfNeeded()
}, completion: nil)
}
}
Here is my code snippet for MENUCELL:-
import UIKit
//MARK:- CollectionViewBaseCell
class CollectionViewBaseCell : UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {}
}
//MARK:- MenuCell
class MenuCell : CollectionViewBaseCell {
//MARK:- Properties
var menuName : String? {
didSet {
label.text = menuName
}
}
let label : UILabel = {
let lbl = UILabel()
lbl.translatesAutoresizingMaskIntoConstraints = false
lbl.text = "Label"
return lbl
}()
//MARK:- default methods
override func setupViews() {
addSubview(label)
//x,y,w,h Constraint
label.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
}
TRY THIS:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == self.collectionView{
print( scrollView.contentOffset.x ) // use this contentOffset
}
}

Adding 'n' number of collection view to UIStackView in swift

I have a ViewController Class where I'm putting scrollView and adding stackView as the subview. Now I want to add 'n' number of collectionView inside the stackView. I'm fetching data from server, there will be a different categories. If category A has data, then I need to create one collectionView for that. And I need to handle the data of corresponding collectionView in their class itself.
class ViewController: UIViewController {
var scrollView : UIScrollView!
var stackView : UIStackView!
var responseFullData : JsonFullDataResponse!
var responseData : JsonResponse!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
print("View Controller init")
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidAppear(_ animated: Bool) {
print("View did appear")
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
override func viewDidLoad() {
super.viewDidLoad()
//loading all the data
loadAllJsonData()
//setting up scroll and stack views
setUpScrollAndStackView()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("inside layout")
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
func setUpScrollAndStackView() {
scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[scrollView]|", options: .alignAllCenterX, metrics: nil, views: ["scrollView": scrollView]))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[scrollView]|", options: .alignAllCenterX, metrics: nil, views: ["scrollView": scrollView]))
stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.spacing = 20.0
stackView.axis = .vertical
scrollView.addSubview(stackView)
scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[stackView]|", options: NSLayoutFormatOptions.alignAllCenterX, metrics: nil, views: ["stackView": stackView]))
scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[stackView]", options: NSLayoutFormatOptions.alignAllCenterX, metrics: nil, views: ["stackView": stackView]))
setUpOtherViewsInStack()
}
func setUpOtherViewsInStack() {
if responseFullData.banner?.count != 0 {
print("banner has data")
var bannerCollection : BannerCollectionView = BannerCollectionView() as! BannerCollectionView
bannerCollection.register(UINib.init(nibName: "BannerCell", bundle: nil), forCellWithReuseIdentifier: "BannerCell")
stackView.addArrangedSubview(bannerCollection)
}
}
BannerCollectionView Code
class BannerCollectionView: UICollectionView , UICollectionViewDataSource{
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
print("control is in datasource")
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerCell", for: indexPath) as! BannerCell
cell.backgroundColor = UIColor.blue
return cell
}
}
How do I make this work. In which class and where I should set the delegate and datasource property of BannerCollectionView? How do I initialise this?
As I understand you need to make a for from 0 to count in responseFullData.banner.count adding a collectionView each time
if let count = responseFullData.banner?.count {
for i in 0..<count {
var bannerCollection : BannerCollectionView = BannerCollectionView() as! BannerCollectionView
bannerCollection.register(UINib.init(nibName: "BannerCell", bundle: nil), forCellWithReuseIdentifier: "BannerCell")
stackView.addArrangedSubview(bannerCollection)
}
}
I have added 3 collectionView inside the UIStackView(Vertical stack). The whole view can be scrolled vertically and the collection items can be scrolled either horizontally or vertically.
class HomePageViewController: UIViewController,HeaderViewDelegate {
var scrollView : UIScrollView!
var stackView : UIStackView!
var responseFullData : JsonFullDataResponse!
if responseFullData?.menu?.count != nil{
print("menu has data")
var menuCollection : MenuCollectionView = MenuCollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout.init())
menuCollection.backgroundColor = .white
menuCollection.menuData = (self.responseFullData.menu)!
menuCollection.dataSource = menuCollection.self
menuCollection.delegate = menuCollection.self
createCollectionViews(collectionViewClass: menuCollection, identifier: "MenuCell",height : 175)
}
if responseFullData?.hongbei?.count != nil {
print("hongbei has data")
var hongbeiCollection : HongbeiCollectionView = HongbeiCollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout.init())
hongbeiCollection.dataSource = hongbeiCollection
hongbeiCollection.delegate = hongbeiCollection
hongbeiCollection.allowsSelection = true
hongbeiCollection.backgroundColor = .white
hongbeiCollection.hongbeiData = (self.responseFullData.hongbei)!
addHeaderView(headerTitle : "Hongbei")
createCollectionViews(collectionViewClass: hongbeiCollection, identifier: "HongbeiCell",height : 150)
}
if responseFullData?.freeZone?.count != nil {
print("freezone has data")
var freezoneCollection : FreeZoneCollectionView = FreeZoneCollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout.init())
freezoneCollection.dataSource = freezoneCollection.self
freezoneCollection.delegate = freezoneCollection.self
freezoneCollection.backgroundColor = .white
freezoneCollection.freeZoneData = (self.responseFullData.freeZone)!
addHeaderView(headerTitle : "FreeZone")
createCollectionViews(collectionViewClass: freezoneCollection, identifier: "FreeZoneCell",height : 150)
}
func createCollectionViews(collectionViewClass : UICollectionView, identifier : String,height : CGFloat ){
collectionViewClass.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
collectionViewClass.heightAnchor.constraint(equalToConstant: height).isActive = true
collectionViewClass.register(UINib.init(nibName: identifier, bundle: nil), forCellWithReuseIdentifier: identifier)
collectionViewClass.showsHorizontalScrollIndicator = false
collectionViewClass.showsVerticalScrollIndicator = false
stackView.addArrangedSubview(collectionViewClass)
}
func addHeaderView(headerTitle : String){
let headerView = HeaderView.instanceFromNib() as! HeaderView
headerView.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
headerView.heightAnchor.constraint(equalToConstant: 20).isActive = true
headerView.headerLabel.text = headerTitle
headerView.frame = headerView.frame.offsetBy(dx: 20, dy: 0)
headerView.delegate = self
stackView.addArrangedSubview(headerView)
}
}
class MenuCollectionView: UICollectionView,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
var menuData : [MenuData]!
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
super.init(frame: frame, collectionViewLayout: layout)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
print("Menu")
return menuData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MenuCell", for: indexPath) as! MenuCell
cell.menuLabel.text = menuData[indexPath.item].title!
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{
return CGSize(width: (collectionView.frame.width * 0.175), height: 75)
}
I have a separate class for each collectionView in the stack, where I handle the data source and delegate methods. So I can have any number for collection items I want in each collectionView.

Function not triggering on scroll

I am trying to trigger a certain function in a collection view when I scroll. Basically Im trying to implement pagination so that when it scrolls to the bottom more items are loaded.
override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.item >= allEvents.count - 1 {
// print("paginating for post")
paginationHelper.paginate(completion: { [unowned self] (events) in
self.allEvents.append(contentsOf: events)
DispatchQueue.main.async {
self.collectionView?.reloadData()
}
})
}else{
print("Not paginating")
}
}
This is the entire Function
import Foundation
import UIKit
import Alamofire
import AlamofireNetworkActivityIndicator
import SwiftLocation
import CoreLocation
import AMScrollingNavbar
class HomeFeedController: UICollectionViewController, UICollectionViewDelegateFlowLayout,UIGestureRecognizerDelegate {
// let dropDownLauncher = DropDownLauncher()
var isFinishedPaging = false
let detailView = EventDetailViewController()
let refreshControl = UIRefreshControl()
var emptyLabel: UILabel?
var allEvents = [Event]()
//will containt array of event keys
var eventKeys = [String]()
let customCellIdentifier = "customCellIdentifier"
var grideLayout = GridLayout(numberOfColumns: 2)
lazy var dropDownLauncer : DropDownLauncher = {
let launcer = DropDownLauncher()
launcer.homeFeed = self
return launcer
}()
let paginationHelper = PaginationHelper<Event>(serviceMethod: PostService.showEvent)
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.white
collectionView?.collectionViewLayout = grideLayout
collectionView?.reloadData()
self.collectionView?.contentInset = UIEdgeInsetsMake(15, 0, 0, 0)
navigationItem.title = "Home"
collectionView?.register(CustomCell.self, forCellWithReuseIdentifier: customCellIdentifier)
// self.navigationItem.hidesBackButton = true
let backButton = UIBarButtonItem(image: UIImage(named: "menu"), style: .plain, target: self, action: #selector(handleDropDownMenu))
self.navigationItem.leftBarButtonItem = backButton
// PostService.showEvent(location: User.current.location!) { (event) in
// self.allEvents = event
// print(self.allEvents)
//
// DispatchQueue.main.async {
// self.collectionView?.reloadData()
// }
// }
configureCollectionView()
reloadHomeFeed()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let navigationController = self.navigationController as? ScrollingNavigationController {
navigationController.followScrollView(self.collectionView!, delay: 50.0)
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if let navigationController = navigationController as? ScrollingNavigationController {
navigationController.stopFollowingScrollView()
}
}
override func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
if let navigationController = navigationController as? ScrollingNavigationController {
navigationController.showNavbar(animated: true)
}
return true
}
func handleDropDownMenu(){
dropDownLauncer.showDropDown()
}
//will query by selected category
func categoryFetch(dropDown: DropDown){
navigationItem.title = dropDown.name
paginationHelper.category = dropDown.name
configureCollectionView()
reloadHomeFeed()
}
func reloadHomeFeed() {
self.paginationHelper.reloadData(completion: { [unowned self] (events) in
self.allEvents = events
if self.refreshControl.isRefreshing {
self.refreshControl.endRefreshing()
}
DispatchQueue.main.async {
self.collectionView?.reloadData()
}
})
}
func configureCollectionView() {
// add pull to refresh
refreshControl.addTarget(self, action: #selector(reloadHomeFeed), for: .valueChanged)
collectionView?.addSubview(refreshControl)
}
// need to tell it how many cells to have
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return allEvents.count
}
// need to tell the collection view controller what type of cell we want to return
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let customCell = collectionView.dequeueReusableCell(withReuseIdentifier: customCellIdentifier, for: indexPath) as! CustomCell
let imageURL = URL(string: allEvents[indexPath.item].currentEventImage)
print(imageURL ?? "")
customCell.sampleImage.af_setImage(withURL: imageURL!)
return customCell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//let selectedEvent = self.imageArray[indexPath.row]
//let eventDetailVC
if let cell = collectionView.cellForItem(at: indexPath){
// print("Look here for event name")
// print(detailView.eventName)
detailView.eventKey = allEvents[indexPath.row].key!
detailView.eventPromo = allEvents[indexPath.row].currentEventPromo!
detailView.currentEvent = allEvents[indexPath.row]
present(detailView, animated: true, completion: nil)
//self.navigationController?.pushViewController(detailView, animated: true)
}
print("Cell \(indexPath.row) selected")
}
override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.item >= allEvents.count - 1 {
// print("paginating for post")
paginationHelper.paginate(completion: { [unowned self] (events) in
self.allEvents.append(contentsOf: events)
DispatchQueue.main.async {
self.collectionView?.reloadData()
}
})
}else{
print("Not paginating")
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
//will make surepictures keep same orientation even if you flip screen
// will most likely lock into portrait mode but still good to have
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
grideLayout.invalidateLayout()
}
//Will allow the first two cells that are displayed to be of varying widths
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.item == 0 || indexPath.item == 1 {
return CGSize(width: view.frame.width, height: grideLayout.itemSize.height)
}else{
return grideLayout.itemSize
}
}
func showLeftView(sender: AnyObject?){
print("Button Pressed")
// sideMenuController?.leftViewController = LeftViewController()
//sideMenuController?.showLeftView(animated: true, completionHandler: nil)
}
}
//responsible for populating each cell with content
class CustomCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let sampleImage: UIImageView = {
let firstImage = UIImageView()
firstImage.clipsToBounds = true
firstImage.translatesAutoresizingMaskIntoConstraints = false
firstImage.contentMode = .scaleToFill
firstImage.layer.masksToBounds = true
return firstImage
}()
let nameLabel: UILabel = {
let name = UILabel()
name.text = "Custom Text"
name.translatesAutoresizingMaskIntoConstraints = false
return name
}()
func setupViews() {
addSubview(sampleImage)
backgroundColor = UIColor.white
//addSubview(nameLabel)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": sampleImage]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": sampleImage]))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// responsible for creating the grid layout that you see in the home view feed
class GridLayout: UICollectionViewFlowLayout {
var numberOfColumns:Int = 2
init(numberOfColumns: Int) {
super.init()
// controlls spacing inbetween them as well as spacing below them to next item
self.numberOfColumns = numberOfColumns
self.minimumInteritemSpacing = 3
self.minimumLineSpacing = 5
}
// just needs to be here because swift tells us to
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var itemSize: CGSize{
get{
if collectionView != nil {
let collectionVieweWidth = collectionView?.frame.width
let itemWidth = (collectionVieweWidth!/CGFloat(self.numberOfColumns)) - self.minimumInteritemSpacing
let itemHeight: CGFloat = 200
return CGSize(width: itemWidth, height: itemHeight)
}
return CGSize(width: 100, height: 100)
}set{
super.itemSize = newValue
}
}
}
This is the function that is responsible for triggering the event but it seems to go to the else statement literally every time. Any insight would be helpful

Infinite Scroll in collectionView swift programmatically

i want to infinite scrolling 10 images in collectionView programmatically of swift. the image came from web by json according to my choice. i have been unable to scrolling 20 image in a times.
here is my code
import Foundation
import UIKit
let categoryCellid = "categoryCellid"
class ProductByCategoryCollectionView: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var headercellId = "headercellId"
var callCategoryObject = [Product]()
func getPropductListByCategory(){
// has api code, that was well
}
override func viewDidLoad() {
super.viewDidLoad()
self.getPropductListByCategory()
collectionView?.backgroundColor = .white
navigationItem.title = "Product"
navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil)
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Sort By", style: .plain, target: nil, action: nil)
self.setupHeaderView()
collectionView?.register(ProductByCategoryCollectionViewCell.self, forCellWithReuseIdentifier: categoryCellid)
}
func showCategoryDetailSegue() {
let detailcontroller = UIViewController()
navigationController?.pushViewController(detailcontroller, animated: true)
}
func sortBtnTarget() {
}
func filterBtnTarget() {
}
let dividedLine: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0.4, alpha: 0.4)
return view
}()
let totalItemLabel: UILabel = {
let label = UILabel()
label.text = ""
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 15)
label.backgroundColor = UIColor.white
return label
}()
let dividerLineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.white
return view
}()
func setupHeaderView(){
view.backgroundColor = UIColor(white: 0.4, alpha: 0.4)
dividedLine.frame = CGRect(x: 0, y: 95, width: view.frame.width, height: 1)
totalItemLabel.frame = CGRect(x: 0, y: 55, width: view.frame.width, height: 40)
view.addSubview(totalItemLabel)
view.addSubview(dividedLine)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return callCategoryObject.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: categoryCellid, for: indexPath) as! ProductByCategoryCollectionViewCell
cell.callProductObject4Cell = callCategoryObject[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 172, height: 300)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(32, 10, 0, 10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let controller1 = DetailsController(collectionViewLayout: layout)
navigationController?.pushViewController(controller1, animated: true)
}
}
class ProductByCategoryCollectionViewCell: UICollectionViewCell {
var callProductObject4Cell: Product? {
didSet {
productLabel.text = callProductObject4Cell?.name
// priceLabel.text = String(describing: callProductObject4Cell?.price)
if let price = callProductObject4Cell?.price {
priceLabel.text = "$\(price)"
} else {
priceLabel.text = ""
}
if let profileImageUrl = callProductObject4Cell?.image {
productImage.loadImageUsingUrlString(profileImageUrl)
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupcategoryCell()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let productImage: UIImageView = {
let image = UIImageView()
image.image = UIImage(named: "default")
image.contentMode = .scaleAspectFit
image.layer.borderWidth = 1
image.layer.borderColor = UIColor.orange.cgColor
image.layer.masksToBounds = true
return image
}()
let productLabel: UILabel = {
let label = UILabel()
label.text = "productName"
label.textColor = .black
label.numberOfLines = 0
label.font = UIFont.boldSystemFont(ofSize: 10)
return label
}()
let priceLabel: UILabel = {
let label = UILabel()
// label.backgroundColor = .lightGray
label.text = ""
label.textColor = .orange
label.font = UIFont.systemFont(ofSize: 13)
return label
}()
func setupcategoryCell() {
addSubview(productImage)
addSubview(productLabel)
addSubview(priceLabel)
addConstraintsWithFormat("H:|[v0]|", views: productImage)
addConstraintsWithFormat("V:|[v0(230)]-2-[v1][v2(10)]-5-|", views: productImage,productLabel, priceLabel)
addConstraintsWithFormat("H:|[v0]|", views: productLabel)
addConstraintsWithFormat("H:|[v0]|", views: priceLabel)
}
}
Use this code for an infinite UIScrollView:
import Foundation
import UIKit
enum LoadMoreStatus {
case loading
case finished
case haveMore
}
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var verticalDataSource = [String]()
var firstCellid = "firstcellid"
var firstFooterCellid = "firstfootercellid"
var numberOfCells = 5
var loadingStatus = LoadMoreStatus.haveMore
func reloadData() {
//numberOfCells = 10
collectionView?.reloadData()
if numberOfCells > 0 {
collectionView?.scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: true)
}
}
func loadMore() {
if numberOfCells >= 40 {
// here will show untill finished number
loadingStatus = .finished
collectionView?.reloadData()
return
}
// Replace code with web service and append to data source
Timer.schedule(delay: 2) { timer in
self.numberOfCells += 2
self.collectionView?.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.automaticallyAdjustsScrollViewInsets = false
collectionView?.register(VerticalCollectionViewCell.self, forCellWithReuseIdentifier: firstCellid)
collectionView?.register(VerticalCollectionViewCell2.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: firstFooterCellid)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK - Rotation methods
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
var text=""
switch UIDevice.current.orientation {
case .portrait:
text="Portrait"
case .portraitUpsideDown:
text="PortraitUpsideDown"
case .landscapeLeft:
text="LandscapeLeft"
case .landscapeRight:
text="LandscapeRight"
default:
text="Another"
}
NSLog("You have moved: \(text)")
collectionView?.reloadData()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numberOfCells
}
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(indexPath.row==numberOfCells-1) {
if loadingStatus == .haveMore {
self.perform(#selector(ViewController.loadMore), with: nil, afterDelay: 0)
}
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: firstCellid, for: indexPath) as! VerticalCollectionViewCell
cell.menuHeaderLabel.text = "Labet text no \(indexPath.item)"
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.view.frame.width, height: 100)
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var footerView:VerticalCollectionViewCell2!
if (kind == UICollectionElementKindSectionFooter) && (loadingStatus != .finished) {
footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: firstFooterCellid, for: indexPath) as! VerticalCollectionViewCell2
}
return footerView
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return (loadingStatus == .finished) ? CGSize.zero : CGSize(width: self.view.frame.width, height: 50)
}
}
class VerticalCollectionViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupCell()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let menuHeaderLabel: UILabel = {
let label = UILabel()
label.text = "lable text"
label.textColor = .orange
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 15)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setupCell() {
addSubview(menuHeaderLabel)
// addTaskButton.addTarget(self, action: #selector(MenuHeader.addTask), for: .touchUpInside)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": menuHeaderLabel]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-5-[v0(30)]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": menuHeaderLabel]))
}
}
class VerticalCollectionViewCell2: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
setupCell()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let menuHeaderLabel: UILabel = {
let label = UILabel()
label.text = "loadin more waiting"
label.textColor = .green
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 15)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setupCell() {
addSubview(menuHeaderLabel)
// addTaskButton.addTarget(self, action: #selector(MenuHeader.addTask), for: .touchUpInside)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": menuHeaderLabel]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-5-[v0(30)]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": menuHeaderLabel]))
}
}
extension Timer {
class func schedule(delay: TimeInterval, handler: #escaping (Timer!) -> Void) -> Timer {
let fireDate = delay + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, 0, 0, 0, handler)
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
return timer!
}
class func schedule(repeatInterval interval: TimeInterval, handler: #escaping (Timer!) -> Void) -> Timer {
let fireDate = interval + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, interval, 0, 0, handler)
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
return timer!
}
}

iOS CollectionView Header doesn't show

Im trying to add a segmented control onto my header but I am having trouble doing this. In this example to make things simpler I am adding a Label but that is also not showing. Can someone tell me why this is not happening?
import UIKit
class SessionsViewController: UICollectionViewController , UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
prepareCollectionView()
view.backgroundColor = UIColor.white
navigationController?.navigationBar.isTranslucent = true
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Log Out", style: .plain, target: self, action: #selector(handleLogout))
navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "plus") , style: .plain, target: self, action: nil)
navigationItem.rightBarButtonItem?.tintColor = UIColor.honePalette.accent
}
func prepareSegmentedControll()->UISegmentedControl{
let items = ["Future Sessions", "Past Sessions"]
let control = UISegmentedControl(items: items)
control.selectedSegmentIndex = 0
control.tintColor = UIColor.honePalette.accent
let font = UIFont.systemFont(ofSize: 12)
control.setTitleTextAttributes([NSFontAttributeName: font], for: .normal)
return control
}
func prepareCollectionView(){
collectionView?.backgroundColor = UIColor.white
collectionView?.alwaysBounceVertical = true
collectionView?.register(sessionsInfo.self, forCellWithReuseIdentifier: "cellId")
}
// return of the number per item per section
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
//this is when the collection is clicked
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let indexPath = collectionView.indexPathsForSelectedItems
print("this is index path:", indexPath)
}
// this is the cell of the collection returning initialized with the SessionsInfo
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as? sessionsInfo
myCell?.sessionLabel.text = "cell \(indexPath.row)"
return myCell!
}
// this is when the size of the cell returns
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width - 10, height: 80)
}
// return supplementary view
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath)
let label = UILabel(frame: headerView.bounds)
label.text = "Top View"
label.font = UIFont(name: "helvetica", size: 12)
label.textAlignment = .center
headerView.addSubview(label)
//headerView.headerLabel.text = "header"
return headerView
}
func handleLogout(){
BaseServices.baseServices.signOut()
present(LoginViewController(), animated: true, completion: nil)
}
}
class headerInfo : UICollectionReusableView{
override init(frame: CGRect) {
super.init(frame: frame)
setupHeader()
}
var headerLabel : UILabel = {
let label = UILabel()
label.text = "HEADER"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupHeader(){
backgroundColor = UIColor.honePalette.raindrops
addSubview(headerLabel)
addConstraints(NSLayoutConstraint.constraints( withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":headerLabel]))
addConstraints(NSLayoutConstraint.constraints( withVisualFormat: "V:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":headerLabel]))
}
}
class sessionsInfo: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupSessions()
}
var sessionLabel : UILabel = {
let label = UILabel()
label.text = "sessionView"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var sessionTimeLabel : UILabel = {
let label = UILabel()
label.text = ""
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var sessionLocationLabel : UILabel = {
let label = UILabel()
label.text = ""
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setupSessions(){
backgroundColor = UIColor.honePalette.raindrops
addSubview(sessionLabel)
addConstraints(NSLayoutConstraint.constraints( withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":sessionLabel]))
addConstraints(NSLayoutConstraint.constraints( withVisualFormat: "V:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":sessionLabel]))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I tried your code in a new project, and you are missing two key steps: registering the supplementary view and setting the size of your header.
In your prepareCollectionView function, you also need to register the header view:
collectionView?.register(headerInfo.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header")
You also need to implement another delegate function giving the size of your header view:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: 100, height: 100) // fix to be your intended size
}
Here is proof that it works. (I didn't have access to your custom colors, which is why everything is orange and gray.)

Resources