How to add multiple collection view in a view - ios

I am trying to incorporate 2 collection views into same view. I implemented everything and noticed that the data that is loading in the second collection view is the same as the first collection view.
Here is the code that i am trying out
class DashBoardMainSection1CollectionViewCellClass: UICollectionViewCell
{
#IBOutlet weak var DashBoardMainSection1CollectionViewImageListingViewOutlet : UIImageView!
#IBOutlet weak var DashBoardMainSection1CollectionViewLabelOutlet : UILabel!
}
class DashBoardMainSection2CollectionViewCellClass: UICollectionViewCell
{
#IBOutlet weak var DashBoardMainSection2CollectionViewImageListingViewOutlet : UIImageView!
#IBOutlet weak var DashBoardMainSection2CollectionViewLabelOutlet : UILabel!
}
private let reuseIdentifierDashBoardMainSection1Cell = "dashBoardMainSection1CollectionViewCellIdentifier"
private let reuseIdentifierDashBoardMainSection2Cell = "dashBoardMainSection2CollectionViewCellIdentifier"
class DashBoardViewControllerMain: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout
{
#IBOutlet weak var DashBoardMainSection1CollectionViewOutlet : UICollectionView!
#IBOutlet weak var DashBoardMainSection2CollectionViewOutlet : UICollectionView!
override func viewDidLoad()
{
super.viewDidLoad()
DashBoardMainSection1CollectionViewOutlet.delegate = self;
DashBoardMainSection2CollectionViewOutlet.delegate = self;
DashBoardMainSection1CollectionViewOutlet.dataSource = self;
DashBoardMainSection2CollectionViewOutlet.dataSource = self;
// Do any additional setup after loading the view.
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
var count:Int?
if (self.DashBoardMainSection1CollectionViewOutlet) != nil{
count = 10
}
//if (self.DashBoardMainSection2CollectionViewOutlet) != nil{
else{
count = 5
}
return count!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let collectionView = self.DashBoardMainSection1CollectionViewOutlet{
let cell:DashBoardMainSection1CollectionViewCellClass = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierDashBoardMainSection1Cell, for: indexPath) as! DashBoardMainSection1CollectionViewCellClass
cell.DashBoardMainSection1CollectionViewImageListingViewOutlet.image = UIImage(named:"Apple.png")
cell.DashBoardMainSection1CollectionViewLabelOutlet.text = "FIRST"
return cell
}
else{
let cell2:DashBoardMainSection2CollectionViewCellClass = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierDashBoardMainSection2Cell, for: indexPath) as! DashBoardMainSection2CollectionViewCellClass
cell2.DashBoardMainSection2CollectionViewImageListingViewOutlet.image = UIImage(named:"Logo-Disabled.png")
cell2.DashBoardMainSection2CollectionViewLabelOutlet.text = "SECOND"
return cell2
}
}
When i run the project both the collection views are showing Apple picture and the cell count is 10.
Can someone help me to solve this issue...

Please manage both collectionview with tag. Give tag to both collectionview on viewDidLoad method or from storyboard. Now make conditions based on tag.
Example :-
DashBoardMainSection1CollectionViewOutlet.tag = 1
DashBoardMainSection2CollectionViewOutlet.tag = 2
if collectionView.tag == 1 {
return 10
} else {
return 5
}

The problem is in the if statement:
It should be like this:
if collectionView == self.DashBoardMainSection1CollectionViewOutlet{
//code
}
With this code, you check if the collectionView passed by the parameter is the first collectionView.
With your original code, you were making new constant named collectionView and assigning it with your first collectionView.

Because your condition if (self.DashBoardMainSection1CollectionViewOutlet) != nil, will always return true and code for if block will only execute everytime.
Try this:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
var count = 0
if (collectionView == self.DashBoardMainSection1CollectionViewOutlet) {
count = 10
}
// if (collectionView == self.DashBoardMainSection2CollectionViewOutlet)
else {
count = 5
}
return count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (collectionView == self.DashBoardMainSection1CollectionViewOutlet){
let cell:DashBoardMainSection1CollectionViewCellClass = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierDashBoardMainSection1Cell, for: indexPath) as! DashBoardMainSection1CollectionViewCellClass
cell.DashBoardMainSection1CollectionViewImageListingViewOutlet.image = UIImage(named:"Apple.png")
cell.DashBoardMainSection1CollectionViewLabelOutlet.text = "FIRST"
return cell
}
else{
let cell2:DashBoardMainSection2CollectionViewCellClass = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierDashBoardMainSection2Cell, for: indexPath) as! DashBoardMainSection2CollectionViewCellClass
cell2.DashBoardMainSection2CollectionViewImageListingViewOutlet.image = UIImage(named:"Logo-Disabled.png")
cell2.DashBoardMainSection2CollectionViewLabelOutlet.text = "SECOND"
return cell2
}
}

If you get same data for both UICollectionView it means you are using the same DataSource.
Define a separate DataSource for each UICollectionView
And you should do the same for the Delegate except if you need to implement same actions for both.

Related

IN secondViewController there are 4 textField . I want check this textField value with firstviewController collection view cell

I have collection view in my FirstViewController and i want to pass the data from collection view cell to next secondViewController textField.
There are four text field and i have design this textField in XIB and load to the secondViewController.
Basically i have to check textField data to the collection View cell Label which is in array.
Here is my code
import UIKit
class BackUpWord{
var label: String
var index: String
init(label:String, index:String) {
self.label = label
self.index = index
}
}
class FirstViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
private var seed : Seed!
private var words : [String]!
var backupWords:[BackUpWord] = []
override func viewDidLoad() {
super.viewDidLoad()
cellIndex = 1
self.collectionView.isPagingEnabled = true
let entropy = Data.randomBytes(length: 32)
self.seed = Seed.init(entropy: entropy)!
words = self.seed.toBIP39Words()
var index = 1
for item in words! {
backupWords.append(BackUpWord.init(label: item, index: index.description))
index = index + 1
}
}
extension FirstViewController: UICollectionViewDelegate, UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return backupWords.count/2
return words.count/2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! LabelCollectionViewCell
let even = backupWords[indexPath.row*2]
let odd = backupWords[indexPath.row*2+1]
cell.backUpWordFirst.text = even.label
cell.backUPWordSecond.text = odd.label
cell.index.text = even.index
cell.index2.text = odd.index
return cell
}
}
Use didSelect delegate of collectionView:
func collectionView(UICollectionView, didSelectItemAt: IndexPath) {
var backupWord: BackUpWord = backupWords[indexPath.row]
let nextViewController = NextViewController = // Get next controller
// Assign values to nextViewController
// Push to next controller and assign values to textfields.
}

Why my collection view disappear when updating the stepper value?

here is my simplified code in my view controller
class WishListVC: UIViewController {
#IBOutlet weak var wishListCollectionView: UICollectionView!
private var products = [Product]()
private var selectedProduct : Product?
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: - cell Delegate
extension WishListVC : ListProductCellDelegate {
func addToCartButtonDidTapped(at selectedIndexPath: IndexPath, collectionView: UICollectionView) {
guard let userOrder = userOrder else {return}
let selectedProduct = products[selectedIndexPath.item]
Order.addProductToOrderRealmDatabase(userOrder: userOrder, selectedProduct: selectedProduct)
wishListCollectionView.reloadData()
updateBadgeOnCartTabBar()
}
func stepperButtonDidTapped(at selectedIndexPath: IndexPath, stepperValue: Int, collectionView: UICollectionView) {
guard let userOrder = userOrder else {return}
let selectedProduct = products[selectedIndexPath.item]
if stepperValue > 0 {
Product.changeProductQuantityInRealmDatabase(selectedProduct: selectedProduct, quantity: stepperValue)
} else {
Order.removeProductFromOrderRealmDatabase(userOrder: userOrder, selectedProduct: selectedProduct)
Product.changeProductQuantityInRealmDatabase(selectedProduct: selectedProduct, quantity: 0)
}
wishListCollectionView.reloadData()
updateBadgeOnCartTabBar()
}
}
//MARK: - Collection View Data Source
extension WishListVC : UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return products.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WishListStoryboardData.CollectionViewIdentifiers.productSliderCell.rawValue, for: indexPath) as? ListProductCell else { return UICollectionViewCell()}
cell.productData = products[indexPath.item]
cell.delegate = self
cell.collectionView = wishListCollectionView
return cell
}
}
and here is the code for my collection view cell:
protocol ListProductCellDelegate {
func addToCartButtonDidTapped(at selectedIndexPath: IndexPath, collectionView : UICollectionView)
func stepperButtonDidTapped( at selectedIndexPath: IndexPath, stepperValue: Int, collectionView : UICollectionView)
}
class ListProductCell: UICollectionViewCell {
#IBOutlet weak var productImageViewAspectRatio: NSLayoutConstraint!
#IBOutlet weak var addToCartButton: UIButton!
#IBOutlet weak var stepper: GMStepper!
var collectionView : UICollectionView?
var delegate: ListProductCellDelegate?
var productData : Product? {
didSet {
updateUI()
}
}
#IBAction func addToCartButtonDidPressed(_ sender: UIButton) {
guard let collectionView = collectionView else {return}
guard let selectedIndexPath = collectionView.indexPathForView(view: sender) else {return}
self.delegate?.addToCartButtonDidTapped(at: selectedIndexPath, collectionView: collectionView)
}
#IBAction func stepperDidTapped(_ sender: GMStepper) {
guard let collectionView = self.collectionView else {return}
guard let selectedIndexPath = collectionView.indexPathForView(view: sender) else {return}
self.delegate?.stepperButtonDidTapped(at: selectedIndexPath, stepperValue: Int(sender.value), collectionView: collectionView)
}
private func updateUI() {
guard let product = productData else {return}
stepper.value = Double(product.quantity)
setLikeButton(product: product)
setCartAndStepperButton()
}
private func setCartAndStepperButton() {
guard let selectedProduct = productData else {return}
func showStepperButton(status: Bool) {
// to decide whether to show stepper or add to cart button.
stepper.isHidden = !status
stepper.isEnabled = status
addToCartButton.isHidden = status
addToCartButton.isEnabled = !status
}
if selectedProduct.quantity == 0 {
showStepperButton(status: false)
} else {
showStepperButton(status: true)
}
}
}
I don't understand why after I tap the stepper for the first time after the 'Add To Cart' disappear, the collection view will disappear.
I don't have collectionView.isHidden in my entire code, but I don't know why my collection view disappear like the file .gif below
http://g.recordit.co/NAEc36MbrM.gif
but if the stepper is already show with some stepper value more than 1, then it will make my collection view dissapear like the gif below
http://recordit.co/SLdqf1ztFZ.gif
the minimum stepper value is set to be 1.
If I change the collection view reload data wishListCollectionView.reloadData() in the stepperButtonDidTapped method above to be just reload data in certain cell only using wishListCollectionView.reloadItems(at: [selectedIndexPath]) the problem will be solved, but the stepper value seems it will be updated little slower, and it looks laggy.
I don't know how to trace the last line that will be executed so it makes my collection view disappears.
and if I reload the data in the main thread using:
DispatchQueue.main.async {
self.wishListCollectionView.reloadData()
}
it won't make the collection view disappear, but If I edit the cell index 4 it will affect the cell index 1 like gif here: http://g.recordit.co/6802BJDdtx.gif
I change the number in the fifth cell but it will automatically change the second cell.
Note to:
Use Xcode Ui Debugging tool and check if your collectionView is hidden or empty
Realm is realTime database ,any changes you make in database will be applied
on your arrays too(like products array)
The reason of stepper problem is becouse of :
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WishListStoryboardData.CollectionViewIdentifiers.productSliderCell.rawValue, for: indexPath) as? ListProductCell else { return UICollectionViewCell()}
and your using stepperButtonDidTapped delegete inside of cell.
declure your cells once and store them inside array,like below:
var cellArray:[ListProductCell]=[]
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (cellArray.count > indexPath.row){
return cellArray[indexPath.row]
}else{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WishListStoryboardData.CollectionViewIdentifiers.productSliderCell.rawValue, for: indexPath) as? ListProductCell else { return UICollectionViewCell()}
cell.productData = products[indexPath.item]
cell.delegate = self
cell.collectionView = wishListCollectionView
cellArray.append(cell)
return cell
}}
My case load get data success but not see data when reload.
This problem case born set Height in func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize is less than height cell on storyboard.

Reuse item inside a row when scrolling

I have collectionView inside tableView. collectionView need to horizontal scroll image, tableView for vertical scroll posts. When I had 3 rows I had no problems, but when i create 4 rows i have a problem with scrolling items inside rows. If I start scrolling on 4 row, scrolling is repeated on row 1 and the same thing if i start scrolling on 1 row scrolling is repeating on row 4.
What could be the problem and how to solve it? May be
Can check .gif file. I start on 1 row on name "Oko" and if i scrolling down on 4 row and scroll right collectionCell and return on 1 row i see next image name "City", but there must be name "Oko"
My code:
ViewController:
class PhotoStudiosViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var tableView: UITableView!
var theStudios: [Studio] = []
var filteredStudios: [Studio] = []
var studiosRef: DatabaseReference!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
tableView.estimatedRowHeight = 475
tableView.rowHeight = UITableViewAutomaticDimension
}
override func viewDidLoad() {
super.viewDidLoad()
studiosRef = Database.database().reference(withPath: "PhotoStudios1")
studiosRef.observe(.value, with: { (snapshot) in
for imageSnap in snapshot.children {
let studioObj = Studio(snapshot: imageSnap as! DataSnapshot)
self.theStudios.append(studioObj)
}
self.tableView.reloadData()
})
}
// MARK: - TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != "" {
return filteredStudios.count
}
return theStudios.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! PhotoStudiosTableViewCell
cell.currentPageNumber.text = "1/\(theStudios[indexPath.row].halls.count)"
if searchController.isActive && searchController.searchBar.text != nil {
cell.theHalls = filteredStudios[indexPath.row].halls
} else {
cell.theHalls = theStudios[indexPath.row].halls
}
cell.nameLabel.text = theStudios[indexPath.row].studioName
cell.addressLabel.text = theStudios[indexPath.row].studioAddress
cell.logoLabel.sd_setImage(with: URL(string: theStudios[indexPath.row].studioLogo))
cell.didSelectAction = {
(innerPath) in
self.showDetailsView(indexPath, cellPath: innerPath)
}
return cell
}
TableViewCell:
class PhotoStudiosTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UIScrollViewDelegate, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var button: UIButton!
#IBOutlet weak var logoLabel: UIImageView!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var addressLabel: UILabel!
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var currentPageNumber: UILabel!
var didSelectAction: ((IndexPath) -> ())?
var theHalls: [Hall] = [] {
didSet {
collectionView.reloadData()
}
}
var lastContentOffset = CGPoint.zero
override func prepareForReuse() {
super.prepareForReuse()
resetCollectionView()
}
override func awakeFromNib() {
super.awakeFromNib()
currentPageNumber.layer.zPosition = 2
currentPageNumber.layer.cornerRadius = 15.0
currentPageNumber.clipsToBounds = true
}
func resetCollectionView() {
guard !theHalls.isEmpty else { return }
theHalls = []
collectionView.reloadData()
}
// MARK: - CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return theHalls.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as! PhotoStudiosCollectionViewCell2
cell.hallName.text = theHalls[indexPath.item].hallName
cell.priceLabel.text = theHalls[indexPath.item].hallPrice
cell.metrslabel.text = theHalls[indexPath.item].hallMetrs
cell.photoStudioImage.sd_setImage(with: URL(string: theHalls[indexPath.item].hallImage))
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
didSelectAction?(indexPath)
}
}
You're reusing the collection views in your cells, which is correct, but that means the contentOffset is also left from whatever was scrolled to previously when a cell is reused. It should be sufficient to just reset the contentOffset in cellForRowAtIndexPath when you are setting up your cell by doing something like:
cell.collectionView.contentOffset = .zero
One thing worth mentioning is that I do see you have a property called lastContentOffset in your cells that doesn't do anything yet and I suspect you are going to try to use that to persist the offset for a given cell when it scrolls out of view so that you can set it again when it comes back into view (rather than always resetting).
If you are going to do that, having the property in the cell won't work. You'll need to have a list of offsets for each cell stored alongside your data models in the containing view controller. Then you might save the offset for a given cell in didEndDisplayingCell and setting it in cellForRowAtIndexPath instead of .zero as I did above.

reloading visible uicollectionviewcell when nested in uitableviewcell

I have a UICollection that shows a padlock on cells that locked to users who aren't logged in. The user can view the collection and then login in a modal. When the modal dismisses, I am trying to reload the cells of the table and the nested collection to remove the padlocks from the cells.
The visible cells are not refreshing to remove the padlock. When the collection is scrolled, the cells offscreen are correct and show with padlock. I am calling reloaddata() on both the tableview and each nested collectionview.
The code I have is separated to:
UIViewController
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("SectionWorkouts", forIndexPath: indexPath) as! SectionTableViewCell
cell.delegate = self
// Return the workouts count from the section
let intIndex = indexPath.row
let index = workoutSections.startIndex.advancedBy(intIndex)
let currentWorkoutSectionKey = workoutSections.keys[index]
if let currentWorkoutSection = workoutSections[currentWorkoutSectionKey] {
cell.workoutsCollection.dataSource = sectionWorkoutsCell
cell.workoutsCollection.delegate = sectionWorkoutsCell
cell.updateCellWithWorkouts(currentWorkoutSectionKey, workouts: currentWorkoutSection)
}
}
return cell
}
UITableViewCell
class SectionTableViewCell: UITableViewCell,UICollectionViewDelegate, UICollectionViewDataSource {
var workouts = [Workout]()
var delegate: WorkoutCellDelegate?
#IBOutlet weak var sectionTitle: UILabel!
#IBOutlet weak var workoutsCollection: UICollectionView!
func updateCellWithWorkouts(title: String, workouts: [Workout]){
self.sectionTitle.text = title
self.workouts = workouts
dispatch_async(dispatch_get_main_queue(),{
self.workoutsCollection.reloadData()
})
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("SectionWorkoutCell", forIndexPath: indexPath) as! SectionCollectionViewCell
let row = indexPath.row
let workout = workouts[row]
cell.configCell(workout)
return cell
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return workouts.count
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let row = indexPath.row
let feature = workouts[row]
if let delegate = self.delegate{
delegate.didSelectWorkoutCell(feature)
}
}
}
UICollectionViewCell
class SectionCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageContainer: UIView!
#IBOutlet weak var image: UIImageView!
#IBOutlet weak var tintOverlay: UIView!
#IBOutlet weak var padlock: UIImageView!
#IBOutlet weak var workoutTitle: UILabel!
#IBOutlet weak var duration: UILabel!
var locked = true
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func configCell(workout: Workout){
self.workoutTitle.text = workout.name
if workout.type == "Free" || AccountManager.userIsLoggedInMember() {
self.setToUnLocked()
}else{
self.setToLocked()
}
self.layoutIfNeeded()
}
func setToUnLocked(){
locked = false
tintOverlay.alpha = 0
padlock.alpha = 0
}
func setToLocked(){
locked = true
tintOverlay.alpha = 0.6
padlock.alpha = 1
}
}
You should probably move the call to configure the cell to the willDisplayCell: method instead. You can remove it from the cellForItemAtIndexPath method. This is the correct time to configure any visual aspects of the cell to be displayed.
func collectionView(collectionView: UICollectionView,
willDisplayCell cell: UICollectionViewCell,
forItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let row = indexPath.row
let workout = workouts[row]
cell.configCell(workout)
return cell
}
The problem lies in the fact that:
the tableViewCell owns the data that is used for configuring the collectionViewCell.
If you want your collectionViewCell to update without the need for tableView.reloadData, the data that is used for configuring the collectionViewCell(in your case 'workout') must be fetched from elsewhere than from the tableViewCell.

UICollectionView cells with Images inside UITableView prototype

UPDATE: I solved my primary issue of correct images not loading until scrolling on the collectionView. I added a collectionView.reloadData() to the tableView:cellForRowAtIndexPath. I also made some changes to pre-load the sequence array, instead of building it while scrolling through the table (tableView:cellForRowAtIndexPath).
Added the updates to GitHub if you are interested.
https://github.com/Druiced/OpenDeck
I will follow-up once I figure out how to prevent the App from crashing when a dynamic value is placed in the return (if i set this to 15, the app will not crash):
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return count(Array(sequenceArray[collectionView.tag])) / 2
}
ORIGINAL POST:
request for some guidance.
This tutorial helped me realize this must have to do with my DataSource/Delegate. The author builds the cell with addSubview instead of taking advantage of the Xcode prototype cell, which seems like a cool thing, so I'm trying to do it.
http://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell
Any criticism about my approach or failure to follow best practices is welcome.
Each cell in the table has a UICollectionView. Each cell in the Collection View displays an image in order of the saved "Sequence" string. example: "ADKDQDJDTD" link up to AD.png KD.png QD.png JD.png TD.png
I have two issues I can't seem to get past.
numberOfItemsInSection gets whacky when the number of cards is driven by the array length (return handArray.count / 2). If I place a fixed number the app will work, but not very slick.
When the table first comes up, the correct cards do not display until I scroll up and down the table. It also appears the data for each CollectionView is crossing paths as the wrong cards show up when scrolling up and down rapidly.
I'm almost positive this has to do with how my datasource is setup.
DeckTableViewController.swift
import UIKit
import Parse
var deviceID: String?
var noRefresh: Bool?
var sequenceArray: Array<Character>?
class DeckTableViewController: UITableViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var handArray: Array<Character>!
var timeLineData:NSMutableArray = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
noRefresh = false
deviceId = UIDevice.currentDevice().identifierForVendor.UUIDString
}
override func viewDidAppear(animated: Bool) {
if noRefresh == false {
loadData()
noRefresh = true
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return timeLineData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:DeckTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! DeckTableViewCell
let deck:PFObject = timeLineData.objectAtIndex(indexPath.row) as! PFObject
cell.collectionView.dataSource = self
cell.collectionView.delegate = self
let sequenceTemp = deck.objectForKey("Sequence") as! String
handArray = Array(sequenceTemp)
cell.sequenceId.setTitle(deck.objectId, forState: UIControlState.Normal)
cell.cardCountLabel.text = "\((count(sequenceTemp)/2))"
// Date to String Stuff
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "(MM-dd) hh:mm:ss"
cell.timeLabel.text = dateFormatter.stringFromDate(deck.updatedAt!)
let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSizeMake(99, 140)
layout.scrollDirection = UICollectionViewScrollDirection.Horizontal
cell.collectionView.collectionViewLayout = layout
return cell
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return handArray.count / 2
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:TableCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! TableCollectionViewCell
var bcolor : UIColor = UIColor.orangeColor()
cell.layer.borderColor = bcolor.CGColor
cell.layer.borderWidth = 2
cell.layer.cornerRadius = 3
var firstLetter: Character!
var secondLetter: Character!
//Building card file names from Sequence data
if (indexPath.row * 2) + 1 <= handArray.count {
firstLetter = handArray[indexPath.row * 2]
secondLetter = handArray[indexPath.row * 2 + 1]
let imageNameString = "\(firstLetter)\(secondLetter).png"
let front = UIImage(named: imageNameString)
cell.ImageView.backgroundColor = UIColor.orangeColor()
cell.ImageView.image = front
}
return cell
}
DeckTableViewCell.swift
import UIKit
class DeckTableViewCell: UITableViewCell, UITextViewDelegate {
#IBOutlet var collectionView: UICollectionView!
#IBOutlet var sequenceId: UIButton!
#IBOutlet var timeLabel: UILabel!
#IBOutlet var cardCountLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
TableCollectionViewCell.swift
import UIKit
class TableCollectionViewCell: UICollectionViewCell {
#IBOutlet var ImageView: UIImageView!
}
For this example I set (return handArray.count / 2) to a 10 and loaded 3 sequences.
The number in the top center represents the number of cards for each row.
Notice the CollectionView does not update with the right cards, it's picking up data from the other CollectionViews. IF I add bunch more sequences to this mix, when scrolling up and down, the correct cards WILL populate SOMETIMES, but unpredictable.
Thanks for any suggestions, I'm happy to go back to the drawing board. Cheers
Ok lets think this way, your DeckTableViewController acts as datasource for tableview, and DeckTableViewCell acts as datasource for collection view.
with the above thing in mind we create a sample project
i am not going in depth, i am giving example like the tutorial as u go through
lets create a sample project with single view app and in ViewController
past the below code, i took one array of integers which contains some values as how many cells to be appears in collection view. don't forget add tableview and set its datasource and deleagte.
before we are coding to controller class we need some classes like custom tableview cell and custom collection view cell we create them first
create a new file which is the subclass of UICollectionViewCell and name it as CustomCollectionViewCell and with xib file.
class CustomCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var aLabel: UILabel! //to show the card number
#IBOutlet weak var imageView: UIImageView! //imageview i am setting it's background color
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
}
}
and create a outlets for label and image view as in the above code.
Next, create new file subclass of UITableViewCell and name it as CustomTableViewCell with xib file. open up CustomTableViewCell.xib file and drag and drop the collection view and set it's datasource and delegate to cell not the controller.
and create a outlet for the collection view and name it as foldersCollectionView.
pass the below code
import UIKit
class CustomTableViewCell: UITableViewCell,UICollectionViewDataSource,UICollectionViewDelegate {
#IBOutlet weak var foldersCollectionView: UICollectionView!
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
// fatalError("init(coder:) has not been implemented")
super.init(coder: aDecoder)
}
var folderCount:Int?
{
didSet(value)
{
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
//configure our collectionview
var aFlowLayout : UICollectionViewFlowLayout = UICollectionViewFlowLayout()
aFlowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal
aFlowLayout.itemSize = CGSizeMake(60.0, 90.0)
aFlowLayout.minimumLineSpacing = 10.0
aFlowLayout.minimumInteritemSpacing = 0.0
aFlowLayout.sectionInset = UIEdgeInsetsMake(2, 9, 0, 10)
foldersCollectionView.collectionViewLayout = aFlowLayout
foldersCollectionView.registerClass(CustomCollectionViewCell.self, forCellWithReuseIdentifier: "FOLDER_CELL")
var cNib:UINib? = UINib(nibName: "CustomCollectionViewCell", bundle: nil)
foldersCollectionView.registerNib(cNib, forCellWithReuseIdentifier: "FOLDER_CELL")
foldersCollectionView.frame = self.bounds
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
class func CreateCustomCell() -> CustomTableViewCell
{
var nibElements: Array = NSBundle.mainBundle().loadNibNamed("CustomTableViewCell", owner: self, options: nil)
var item: AnyObject?
for item in nibElements
{
if item is UITableViewCell
{
return item as CustomTableViewCell
}
}
return item as CustomTableViewCell
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell :CustomCollectionViewCell? = collectionView.dequeueReusableCellWithReuseIdentifier("FOLDER_CELL", forIndexPath: indexPath) as? CustomCollectionViewCell
//hear u can modify which image to be displayed in the collection view cell
cell?.aLabel.text = "Card:\(indexPath.row)"
return cell!
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return folderCount!
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
}
now we are going the code the ViewController class
now just past the below code
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
var cardCountArray:[Int] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
cardCountArray = [5,15,6,12,7,10]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return cardCountArray.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell:CustomTableViewCell? = tableView.dequeueReusableCellWithIdentifier("CELL") as? CustomTableViewCell;
if(cell == nil)
{
cell = CustomTableViewCell.CreateCustomCell()
}
cell?.folderCount = cardCountArray[indexPath.section]
cell?.foldersCollectionView.reloadData()
cell?.clipsToBounds = true
return cell!;
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return 100.0
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var headerView:UIView = UIView(frame: CGRectMake(0, 0, tableView.bounds.size.width, 70.0))
var labelTitle:UILabel = UILabel(frame: CGRectMake(0, 0, tableView.bounds.size.width, 35))
var descriptionTitle:UILabel = UILabel(frame: CGRectMake(0, 20,tableView.bounds.size.width , 30))
headerView.addSubview(labelTitle)
headerView.addSubview(descriptionTitle)
labelTitle.text = "TOTAL_CARDS in section:\(section)"
descriptionTitle.text = "This CARD_SECTION contains \(cardCountArray[section]) CARDS"
return headerView
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50.0
}
}
result will be like below
if any thing missing please let me know
For your comment I have an array, for example, ["2C3C4C5C6C7C", "AD2D3D4D5D", "9H8H7H"]
for this u need to make below modification
//for first row u get like this
//the string for the row is 2C3C4C5C6C7C
//stringForCell = "2C3C4C5C6C7C"
//2C
//3C
//4C
//5C
//6C
//7C
//for other cells u can get like below
//the string for the row is AD2D3D4D5D
//stringForCell = "AD2D3D4D5D"
//AD
//2D
//3D
//4D
//5D
//the string for the row is 9H8H7H
//stringForCell = "9H8H7H"
//9H
//8H
//7H
//in controller controller class define array of string
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
var cardCountArray:[Int] = []
var stringArray : [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
stringArray = ["2C3C4C5C6C7C", "AD2D3D4D5D", "9H8H7H"]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
// return cardCountArray.count
return stringArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell:CustomTableViewCell? = tableView.dequeueReusableCellWithIdentifier("CELL") as? CustomTableViewCell;
if(cell == nil)
{
cell = CustomTableViewCell.CreateCustomCell()
}
//cell?.folderCount = cardCountArray[indexPath.section]
cell?.stringForCell = stringArray[indexPath.section];
cell?.foldersCollectionView.reloadData()
cell?.clipsToBounds = true
return cell!;
}
//in custom tableview cell add a string variable
class CustomTableViewCell: UITableViewCell,UICollectionViewDataSource,UICollectionViewDelegate {
#IBOutlet weak var foldersCollectionView: UICollectionView!
var stringForCell:String = "" //add the string to hold the string
//rest of the code
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell :CustomCollectionViewCell? = collectionView.dequeueReusableCellWithReuseIdentifier("FOLDER_CELL", forIndexPath: indexPath) as? CustomCollectionViewCell
var str:NSString = stringForCell
var length = str.length
var totalLlength:Int = length/2
var indexStart = indexPath.row * (2);
var aRange = NSMakeRange(indexStart, 2)
var cardString:NSString = str.substringWithRange(aRange)
println(cardString)
cell?.aLabel.text = "Card: \(cardString)"
return cell!
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
println("the string for the row is \(stringForCell)")
var str:NSString = stringForCell
var length:Int = str.length
return length / 2
//return folderCount!
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
i written a detailed post about how to add collection view inside custom table view cell hear hope this gives more detailed explanation than this post.

Resources