How to display different cells below CollectionView header depending on users selection? - ios

EDIT: I am trying to re-create the instagram/twitter profile page. So if the current way I am trying to do it won't work, feel free to tell me how to recreate these profile pages in a totally different way.
I have set up a UICollectionView with a header. Inside this header, there is a menuBar that has two different selection options. If the user selects the first index, the menuBar returns 0. If the user selects the second index, the menuBar returns 1.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CoverCell
return cell
}
Here is a picture of the menu bar and the collectionview cells below it:
I also have this code to set up the cells:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let menuBarIndex = profileMenuBarSelectionIndex.menuBarIndexSelection
var cell: UICollectionViewCell
switch menuBarIndex {
case 0:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test1CellId, for: indexPath) as! test1Cell
case 1:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test2CellId, for: indexPath) as! test2Cell
default:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test3CellId, for: indexPath) as! test3Cell
}
return cell
}
EDIT 2: I have now added this code, where myTestAction is the delegate function of testAction in a different file.
var index: Int = 0
func testAction() {
index = index == 1 ? 0 : 1
collectionView.reloadData()
}
func myTestAction() {
delegate?.testAction()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
switch indexPath.row{
case 0:
menuBarIndexSelection = 0
menuBarIndexChangeFlag = 1
case 1:
menuBarIndexSelection = 1
menuBarIndexChangeFlag = 2
case 2:
menuBarIndexSelection = 2
menuBarIndexChangeFlag = 3
default:
menuBarIndexSelection = 0
}
myTestAction()
}
I want to be able to display different cells below the header depending on which value menuBar returns. How would I do this?
OR
How can I recreate the Instagram profile page?

Put a check on cellForRow and supplimentaryViewsForHeader for menuBar value. And when the value of menuBar changes just reload the table. At the time of reloading the data will be shown according to your check present in dataSources.
// MENU BAR BUTTON CLICK
self.collectionView.reloadData()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
if menuBar == 0 {
// show this image
}else{
//show that image
}
return cell
}

Try this,
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//Take a variable menuBar. when the user tap change it's value to 0 or 1 and reload collection view when user tap on menu button.
if menuBar == 0 {
return 0
}else{
return 1
}

The reason for getting the compiler error you describe is that you create 4 different variables called "cell":
var cell: UICollectionViewCell
switch menuBarIndex {
case 0:
var cell = ...
case 1:
var cell = ...
default:
var cell = ...
}
return cell
The cell instance you return at the end of the function was never assigned a value.
Assigning the first cell variable instead of creating new ones in each case should fix the compiler error:
var cell: UICollectionViewCell
switch menuBarIndex {
case 0:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test1CellId, for: indexPath) as! test1Cell
case 1:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test2CellId, for: indexPath) as! test2Cell
default:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test3CellId, for: indexPath) as! test3Cell
}
return cell
------------------------- EDIT ---------------------
The answer above fixed the compiler error but not the actual question.
I created a small sample project that does what is needed and works fine. Maybe that helps with figuring out the problem. I just created a single view application in Xcode, this is the code for the one view controller in the project and the cells:
class ViewController: UIViewController, UICollectionViewDataSource {
var index: Int = 0
var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(frame: CGRect(x: 10, y: 10, width: 200, height: 50))
btn.backgroundColor = .green
btn.setTitle("Change cell color", for: .normal)
btn.setTitleColor(.black, for: .normal)
btn.addTarget(self, action: #selector(testAction), for: .touchUpInside)
view.addSubview(btn)
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
layout.scrollDirection = .vertical
collectionView = UICollectionView(frame: CGRect(x: 0, y: 60, width: view.frame.width, height: view.frame.height - 60), collectionViewLayout: layout)
collectionView?.backgroundColor = .white
collectionView?.dataSource = self
collectionView?.register(RedCell.self, forCellWithReuseIdentifier: "red")
collectionView?.register(BlueCell.self, forCellWithReuseIdentifier: "blue")
view.addSubview(collectionView!)
}
func testAction() {
index = index == 1 ? 0 : 1
collectionView?.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell: UICollectionViewCell
switch index {
case 0:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "red", for: indexPath)
case 1:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "blue", for: indexPath)
default:
cell = UICollectionViewCell()
}
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 7
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
return CGSize(width: 50, height: 50)
}
}
class RedCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .red
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class BlueCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .blue
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Related

new view created with every collectionView cell tap instead of updating the existing one

I want to have this ring progress view (cocoa pod) inside collectionView Cells. When you tap on a cell, the progress should increase by 0.1 (0.0 = 0% Progress, 1.0 = 100% progress).
Unfortunately, it seems like it always creates a new progress view above the old one, because the shade of red is getting darker and you can see a second/third/.. ring. I have no idea how I can fix this.
This is my code: (Cell class and CollectionViewController Class)
import UIKit
private let reuseIdentifier = "Cell"
class myCollectionViewController: UICollectionViewController {
#IBOutlet var myCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
myCollectionView.reloadData()
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 7
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! myCollectionViewCell
if(indexPath.item != 0){
cell.setProgress(progress: 1 / Double(indexPath.item))
}
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! myCollectionViewCell
cell.setProgress(progress: cell.getProgress() + 0.1)
myCollectionView.reloadData()
}
}
import UIKit
import MKRingProgressView
class myCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var ringView: UIView!
let ringsize = 150
var ringProgressView = RingProgressView()
override func layoutSubviews() {
ringProgressView = RingProgressView(frame: CGRect(x: 0, y: 0, width: ringsize, height: ringsize))
ringProgressView.startColor = .red
ringProgressView.endColor = .magenta
ringProgressView.ringWidth = CGFloat(ringsize) * 0.15
ringProgressView.progress = 0.0
ringProgressView.shadowOpacity = 0.5
ringView.addSubview(ringProgressView)
}
}
extension myCollectionViewCell{
func setProgress(progress: Double){
UIView.animate(withDuration: 0.5){
self.ringProgressView.progress = progress
}
}
func getProgress() -> Double{
return self.ringProgressView.progress
}
}
This is what it looks like when launch (the progress it for testing at (1/indexpath.item):
And this is what it looks like when I TAP THE BOTTOM LEFT CICLE 1 TIME:
I can see with the animation, that a second ring overlays the first ring on the bottom left circle with same progress. Somehow the other rings also changed... why? You can even see the second ring on some other circles. You can also see that the shade of the red went a little bit darker. When I tap multiple times, everything becomes completely (intensive) red.
Thanks for any help!
Simple usage:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! myCollectionViewCell
cell.setProgress(progress: cell.getProgress() + 0.1)
}
you should not call like this:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! myCollectionViewCell
cell.setProgress(progress: cell.getProgress() + 0.1)
myCollectionView.reloadData()
}
because of cell reuse mechanism,
you call
collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! myCollectionViewCell
you get a cell of objects pool, namely a cell of newly created , or a cell created and not visible
myCollectionView.reloadData()
that's worse, call this, just do resetting,
because you do not maintain the data.
You can use pattern mark & config
in method didSelectItemAt , update the data
in method cellForItemAt , update the UI, use myCollectionView.reloadData() to trigger
var progressData = [IndexPath: Double]()
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! myCollectionViewCell
if let val = progressData[indexPath]{
cell.setProgress(progress: val)
}
else{
var value = Double(0)
if(indexPath.item != 0){
value = 1 / Double(indexPath.item)
}
progressData[indexPath] = value
cell.setProgress(progress: value)
}
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
progressData[indexPath]! += 0.1
myCollectionView.reloadData()
}

insert/ delete sections in cells UICollectionView

Good afternoon,
I am trying to create expandable/ collapsible cells in a UICollectionViewController. The cells expand and collapse correctly. However, the information each cell holds stays present on the screen in the background. I will show pictures to explain. I am trying to delete the information from the view if the user collapses the cell, and insert it back if the user expands that cell.
The images below express the process of the cell starting in a collapsed state, expanding that cell, them collapsing that cell again. (note: this happens to every cell not just the first cell I clicked.
the first image is when the view loads and the cells are in the original collapsed state.
this second image shows when the user taps on the cell to expand it.
the third image shows when the user tries to collapse the cell.
the code that I use to expand and collapse the cells are below
fileprivate let cellId = "cellId"
fileprivate let headerId = "headerId"
fileprivate let profID = "profID"
private let headerIdentifier = "userProfileHeader"
private let sectionIdentifier = "sectionHeader"
var section:Int?
var expandSection = [Bool]()
var items = [String]()
fileprivate func setupCollectionView() {
collectionView.backgroundColor = .white
collectionView.contentInsetAdjustmentBehavior = .never
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
self.expandSection = [Bool](repeating: false, count: self.items.count)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(userProfileHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerIdentifier)
collectionView.register(sectionHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: sectionIdentifier)
}
fileprivate func registerCollectionView() {
collectionView.register(profCell.self, forCellWithReuseIdentifier: "profCell")
self.collectionView.register(userProfileHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerIdentifier)
self.collectionView.register(sectionHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: sectionIdentifier)
}
var headerView: userProfileHeader?
var sectionView: sectionHeader?
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as? userProfileHeader
if let user = self.user {
headerView?.myUser = user
} else if let userToLoad = self.userToLoad {
headerView?.myUser = userToLoad
}
return headerView!
} else {
let sectionViews = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: sectionIdentifier, for: indexPath) as? sectionHeader
let categories = ["Skills, Preferences", "Bio", "Reviews"]
sectionViews!.headerLabel.text = categories[indexPath.section]
sectionViews!.backgroundColor = .lightGray
return sectionViews!
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return .init(width: view.frame.width, height: 340)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.expandSection[indexPath.row] = !self.expandSection[indexPath.row]
self.collectionView.reloadItems(at: collectionView.indexPathsForSelectedItems!)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "profCell", for: indexPath) as! profCell
if indexPath.row == 0 {
cell.educationView.text = user.education
cell.skillsView.text = user.skills
cell.preferencesView.text = "wassup bitches"
} else if indexPath.row == 1 {
cell.bioLabel.text = user.bio
} else if indexPath.row == 2 {
cell.labels.text = "Reviews"
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if self.expandSection[indexPath.row] {
return CGSize(width: self.view.bounds.width - 20, height: 300)
}else{
return CGSize(width: self.view.bounds.width - 20, height: 80)
}
}
Instead of trying to insert and remove items inside sizeForItemAt(), call reloadSections(_ sections: IndexSet) for the sections that get expanded or contracted. Then implement numberOfItems(inSection section: Int) to return 0 when contracted or items.count when expanded. Use sections to hold the top level items and cells to hold the collapsible sub-items.

How to segue from UICollectionView Cell to another ViewController Swift

Assume I have a user cell. I need to start a ChatViewController for this User. So, I have UICollectionView which presented as raws (1 cell = 1 row). How to segue to ChatViewController from cell?
I don't use InterfaceBuilder at all. Only through code way.
I planned to use didSelectItemAt but I don't have enough swift programming skills to figure out how to use this function for my purpose. When I try to write prepare for segue or performSegue with Identifier inside didSelectItemAt function the Xcode doesn't provide proper autocomplete. My Code is below:
import UIKit
class MyList: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
override init(frame: CGRect) {
super .init(frame: frame)
setUpLocalizedUserList()
}
//Click on User Cell
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Click")
}
//Localized User List (Collection View)
private func setUpLocalizedUserList(){
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 20, right: 0)
layout.minimumLineSpacing = 0
layout.itemSize = CGSize(width: UIScreen.main.bounds.width, height: 80)
let userListFrame = CGRect(x: 0, y: 0, width: Int(UIScreen.main.bounds.width), height: Int(UIScreen.main.bounds.height) - 160)
let myCollectionView:UICollectionView = UICollectionView(frame: userListFrame, collectionViewLayout: layout)
myCollectionView.dataSource = self
myCollectionView.delegate = self
myCollectionView.register(LocalizedUserCell.self, forCellWithReuseIdentifier: "userCell")
myCollectionView.register(GroupChatCell.self, forCellWithReuseIdentifier: "groupCell")
myCollectionView.backgroundColor = UIColor.white
addSubview(myCollectionView)
}
//Number of Section in User List
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
//Lists' Sizes
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (section == 0) ? 5 : 4
}
//Cells content here
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "userCell", for: indexPath) as! LocalizedUserCell
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "groupCell", for: indexPath) as! GroupChatCell
return cell
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Maybe it's important - my users cells are inside another cell.
You can't make a segue from inSide collectionViewCell as present func needs a UIViewController , see here my answer for a table cell , the same logic TableCellNavigate

Change background of specific UICollectionView cells swift

I am trying to change the background of the first two cells in my collection view i have tried this code
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = self.view.frame.width
let height = self.view.frame.height
return CGSize(width: width / 2.2 , height: height / 6)
}
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
MyCollectionView.reloadData()
}
#IBAction func Back(_ sender: Any) {
performSegue(withIdentifier: "fourtothree", sender: nil)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return ScoreArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let MyCell = Cell.viewWithTag(1) as! UILabel
MyCell.text = ScoreArray[indexPath.row]
if indexPath.row == 0 {
Cell.backgroundColor = UIColor.gray
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
}
if indexPath.row == 1 {
Cell.backgroundColor = UIColor.gray
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
}
return Cell
}
It changes the color of the first two cells which is great. however when I rotate to landscape or scroll it changes the background of different cells not just the first two.
Question: How can I change the background of only the first two cells no mater what the user does?
Since your cell get reused, you need to provide the default color for other cell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let MyCell = Cell.viewWithTag(1) as! UILabel
MyCell.text = ScoreArray[indexPath.row]
if indexPath.row == 0 || indexPath.row == 1 {
Cell.backgroundColor = UIColor.gray
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
} else {
Cell.backgroundColor = UIColor.white //change with your default color
}
return Cell
}
you can change the color of ay cell but as in cellForItemAt indexPath function you are using
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell that statement reuse the cell to reduce the memory usage , So to overcome this problem use
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let MyCell = Cell.viewWithTag(1) as! UILabel
MyCell.text = ScoreArray[indexPath.row]
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
if indexPath.row == 0 || indexPath.row == 1 {
Cell.backgroundColor = UIColor.gray
}
else {
Cell.backgroundColor = UIColor.clear
}
return Cell
}

UICollection NumberOfItemsInSections issue with adding a constant to vars

I have two different cell type classes and i'm trying to make the first indexpath with the class PayNowCell, have it remain displayed. While the other cells are of class CheckOutCell. Now the problem is in my func numberofitemsinsection. Currently i'm using return checkout.count but it missing the PayNowCell when view loads. If i make it return checkout.count+1 to always have the PayNowCell available; my program crashes giving me the error index out of bounds. The array checkout is a global var. Can someone explain why and provide a fix? Been stuck on this for a while. Code Below.
class CheckoutController: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
var inventoryTabController: InventoryTabController?
override init(frame: CGRect){
super.init(frame: frame)
setupViews()
NotificationCenter.default.addObserver(forName: .arrayValueChanged, object: nil, queue: OperationQueue.main) { [weak self] (notif) in
self?.collectionView.reloadData()
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func loadItems() -> [Item]? {
return NSKeyedUnarchiver.unarchiveObject(withFile: Item.ArchiveURL.path) as? [Item]
}
func saveItems() {
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(checkout, toFile: Item.ArchiveURL.path)
if !isSuccessfulSave {
print("Failed to save items...")
}
}
func addItem(item: Item) {
items.append(item)
collectionView.reloadData()
}
func editItem(item: Item, index: Int) {
items[index] = item
collectionView.reloadData()
}
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Identify which segue is occuring.
if segue.identifier == "ShowDetail" {
let itemDetailViewController = segue.destination as! AddItemController
// Get the cell that generated this segue.
if let selectedItemCell = sender as? InventoryCell {
let indexPath = collectionView.indexPath(for: selectedItemCell)!
let selectedItem = items[indexPath.row]
itemDetailViewController.item = selectedItem
}
}
else if segue.identifier == "AddItem" {
print("Adding new meal.")
}
}
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.dataSource = self
cv.delegate = self
cv.backgroundColor = UIColor.rgb(r: 247, g: 247, b: 247)
return cv
}()
let cellId = "cellId"
let paynow = "paynow"
func setupViews() {
backgroundColor = .brown
addSubview(collectionView)
addConstraintsWithFormat("H:|[v0]|", views: collectionView)
addConstraintsWithFormat("V:|[v0]|", views: collectionView)
collectionView.indicatorStyle = UIScrollViewIndicatorStyle.white
collectionView.register(PayNowCell.self, forCellWithReuseIdentifier: paynow)
collectionView.register(CheckoutCell.self, forCellWithReuseIdentifier: cellId)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return checkout.count //init number of cells
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "paynow", for: indexPath) as! PayNowCell //init cells
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CheckoutCell //init cells
print("Printing this \(checkout.count)")
cell.item = checkout[indexPath.item]
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//let item = items[indexPath.item]
//inventoryController?.showItemDetailForItem(item: item, index: indexPath.item)
print("selected")
print(indexPath.item)
collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.item == 0 {
return CGSize(width:frame.width, height: 100) //each cell dimensions
}else{
return CGSize(width:frame.width, height: 150) //each cell dimensions
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
It's better to re-arrange your collection view to have 2 sections:
Section 0: PayNow cell (only 1 cell)
Section 1: Checkout cells (using checkout array list)
Then you don't have any confusion about the indexPath.item issue.
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return section == 0 ? 1 : checkout.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "paynow", for: indexPath) as! PayNowCell //init cells
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CheckoutCell //init cells
print("Printing this \(checkout.count)")
cell.item = checkout[indexPath.item]
return cell
}
}
You need to subtract 1 from your cellForRow function. Since you are adding the PayNowCell you are adding one extra indexPath, but currently, you are using the default indexPath given by the dataSource function. That index will always be one higher than the count of your items. By subtracting 1 from the indexPath, you will be back in sync with your itemsArray, taking into account the PayNowCell.
cell.item = checkout[indexPath.item - 1]

Resources