UICollection View - ios

I have a reusable collection view cell. I am trying to set an image at didselect at index path but when i select a cell it return more than cell returning same image.
Here is the code.
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CollectionViewCell
cell.userImage.layer.cornerRadius = cell.userImage.frame.size.width/2
cell.userImage.clipsToBounds = true
return cell
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int{
return 10
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath){
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! CollectionViewCell
cell.userStatusImage.image = UIImage(named: "selectedcontact.png")
collectionView.reloadData()
}

You need to keep track of the selected cells.
var selectedIndexes = [Int]()
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)
if self.selectedIndexes.contains(indexPath.row){
cell.backgroundColor = UIColor.redColor()
}
else{
cell.backgroundColor = UIColor.whiteColor()
}
return cell
}
// MARK: UICollectionViewDelegate
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if selectedIndexes.contains(indexPath.row){
selectedIndexes.removeObject(indexPath.row)
}
else{
selectedIndexes.append(indexPath.row)
}
collectionView.reloadData()
}
Swift array don't have method to removeObject. Here is an extension for that
extension Array {
mutating func removeObject<U: Equatable>(object: U) -> Bool {
for (idx, objectToCompare) in self.enumerate() {
if let to = objectToCompare as? U {
if object == to {
self.removeAtIndex(idx)
return true
}
}
}
return false
}
}

It seems the last line of code collectionView.reloadData() will reload all the cell to initial status since you don't have any place checking whether one specific cell is selected or not.

Related

Swift CollectionView first cell add user button and other cell load from image array

In my case, I am trying to create a UICollcetionView with first cell add button for add user and from second cell I need to load Image array string into another cells. Here, I am using two separate cell but I am not getting first cell into my output. Please provide me solution or another best method.
I am trying to get below output
Multiple Cell Code
// MARK: CollectionView Delegate
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let firstCell = collectionView.dequeueReusableCell(withReuseIdentifier: "addusercell", for: indexPath) as! AddParticipantsCollectionViewCell
return firstCell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "userscollectionview", for: indexPath as IndexPath) as! ParticipantsCollectionViewCell
cell.imageView?.image = self.imageArray[indexPath.row]
return cell
}
}
You need
if indexPath.item == 0 {
// first cell
}
else {
// second cell
cell.imageView?.image = self.imageArray[indexPath.item - 1]
}
Correct dataSource method ( remove it )
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1 // Section should set return 1 or default is optional
}
And change numberOfItemsInSection to
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count + 1
}
If you have two sections in the collectionView you also need to set the number of items in each individual section:
// MARK: CollectionView Delegate
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 1 // return 1 item in cell (+ cell)
} else {
return imageArray.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let firstCell = collectionView.dequeueReusableCell(withReuseIdentifier: "addusercell", for: indexPath) as! AddParticipantsCollectionViewCell
return firstCell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "userscollectionview", for: indexPath as IndexPath) as! ParticipantsCollectionViewCell
cell.imageView?.image = self.imageArray[indexPath.row]
return cell
}
}
I hope it's been of any help.

UICollectionView Disappear

I'm quite new to Swift. My problem is that my UICollectionView is disappearing.
In Xcode, it shows that everything is in place, but when I launch on a simulator or a device it disappears only left with the Navigation Bar and the Tab Bar.
Does anyone know what caused this or how to solve this?
Cheers!
Here is my code:
class User: UICollectionViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return 0
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "Header", for: indexPath) as! UserHeaderView
header.userEmail.text = PFUser.current()!.email
header.userChosenName.text = PFUser.current()!.object(forKey: "nickname") as? String
header.profilePicture.layer.cornerRadius = header.profilePicture.frame.size.width/2
header.profilePicture.clipsToBounds = true
let query = PFUser.current()?.object(forKey: "profilePicture") as! PFFile
query.getDataInBackground { (image, error) in
if error == nil {
header.profilePicture.image = UIImage(data: image!)
}
else {
SVProgressHUD.showError(withStatus: "Something's Wrong...")
}
}
return header
}
You are using the generated class and you have the number of sections 0 and number of rows 0 you have to change those based the count you want them to show
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// The number of sections you have to provide
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// Number of Items in this section at least it should be 1
return 1
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "Header", for: indexPath) as! UserHeaderView
header.userEmail.text = PFUser.current()!.email
header.userChosenName.text = PFUser.current()!.object(forKey: "nickname") as? String
header.profilePicture.layer.cornerRadius = header.profilePicture.frame.size.width/2
header.profilePicture.clipsToBounds = true
let query = PFUser.current()?.object(forKey: "profilePicture") as! PFFile
query.getDataInBackground { (image, error) in
if error == nil {
header.profilePicture.image = UIImage(data: image!)
}
else {
SVProgressHUD.showError(withStatus: "Something's Wrong...")
}
}
return header
}
Edit:
You should have a cellForItemAt indexPath func else app will crash. here is an example of the function
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// this will return an empty cell where you're app will not crash
// but you have to create a cell and populate some data to the cell
return UICollectionViewCell()
}

How to pass data between two cells

After hours of googling it seems that I need a hint from society.
So the problem is:
I have two custom prototype cells. First one contains UICollectionView with 12 cells, second one contains only a label.
My task is to pass indexPath.row from that collectionView from first cell to the label from the second cell.
didSelectItemAtIndexPath: not working or I didn't tuned it properly.
Any ideas on how to implement will be very appreciated!
Here's my code (sorry for poor StackOverflow formatting)
import UIKit
class MainTableViewController: UITableViewController {
var storedOffsets = [Int: CGFloat]()
var descrLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("MainCell", forIndexPath: indexPath) as! MainTableViewCell
let bgImg = UIImageView(image: UIImage(named: "background"))
bgImg.contentMode = UIViewContentMode.ScaleAspectFill
cell.backgroundView = bgImg
return cell
}
else {
let cell = tableView.dequeueReusableCellWithIdentifier("DescriptionCell", forIndexPath: indexPath) as! DescriptionTableViewCell
cell.descriptionLabel.text = self.descrLabel.text
return cell
}
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
guard let tableViewCell = cell as? MainTableViewCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
tableViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
}
override func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
guard let tableViewCell = cell as? MainTableViewCell else { return }
storedOffsets[indexPath.row] = tableViewCell.collectionViewOffset
}
}
extension MainTableViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MainCollectionViewCell", forIndexPath: indexPath) as! MainCollectionViewCell
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("Collection view at row \(collectionView.tag) selected index path \(indexPath.row)")
self.descrLabel.text = "testText"
}
}
I played around in playground and made this.
It's not tested, but it should give you idea.
protocol CustomDelegate{
func passData(data: AnyObject)
}
class CustomColletionView : UICollectionView, UICollectionViewDelegate{
var customDelegate : CustomDelegate!
func didSelectItemAtIndexPath(collectionView : UICollectionView, indexPath : NSIndexPath){
let cell = collectionView.cellForItemAtIndexPath(indexPath)
let someData = ""
customDelegate.passData(someData)
}
}
class ViewController: UITableViewController, CustomDelegate{
var labelCellData : AnyObject?{
didSet{
//reloadCell when data is received
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: 1, inSection: 0)], withRowAnimation: .Bottom)
}
}
func passData(data: AnyObject) {
labelCellData = data
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier:"Indetifier1")
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "simpleCell")
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.row{
case 0:
//this should contain CustomCollectionView
let cell = tableView.dequeueReusableCellWithIdentifier("Indetifier1") as! CustomTableViewCell
cell.collectionView.customDelegate = self
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("simpleCell")
cell?.textLabel?.text = labelCellData as? String
return cell!
default:
break
}
return UITableViewCell()
}
}
class CustomTableViewCell: UITableViewCell {
var collectionView : CustomColletionView!
// You need to implement it
}

How can I have multiple Collection Views in one View Controller?

I want one View Controller to have seven horizontal button scrolls. I've set up the first Collection View, and I repeated the exact process for a second Collection View directly underneath, but I keep getting Thread 1: SIGABRT error. My code for the functional Collection View is here:
class xyViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var tableImages: [String] = ["1.png", "2.png", "3.png", "4.png", "5.png", "6.png"]
override func viewDidLoad() {
// Initialize the collection views, set the desired frames
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tableImages.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:xyCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! xyCollectionViewCell
cell.xyImgCell.image = UIImage(named: tableImages[indexPath.row])
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
println("cell \(indexPath.row) selected")
}
}
It works when I run this.
So when I add a second Collection View underneath, create a new View Controller file to IBOutlet the button's image and a new Collection View Cell file to add the following code, it crashes.
class bwViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var bwTableImages: [String] = ["a", "PlasmaBlast.png", "b.png", "c.png", "d.png", "e.png", "f.png", "g.png", "h.png", "i.png", "j.png"]
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return bwTableImages.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:bwCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell1", forIndexPath: indexPath) as! bwCollectionViewCell
cell.bwImgCell.image = UIImage(named: bwTableImages[indexPath.row])
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
println("cell \(indexPath.row) selected")
}
}
Here is a two-section version of the code you wrote. I'm not sure if it addresses the error you are seeing, but it's how you'd do multiple collection views on one page.
class xyViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var tableImagesOne: [String] = ["1.png", "2.png", "3.png", "4.png", "5.png", "6.png", "7.png", "8.png"]
var tableImagesTwo: [String] = ["1.png", "2.png", "3.png", "4.png", "5.png"]
override func viewDidLoad() {
// Initialize the collection views, set the desired frames
}
func numberOfSectionsInCollectionView(_ collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return tableImagesOne.count
}
else {
return tableImagesTwo.count
}
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let row = indexPath.row
let section = indexPath.section
let cell:xyCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! xyCollectionViewCell
if section == 0 {
cell.xyImgCell.image = UIImage(named: tableImagesOne[row])
}
else if section == 1 {
cell.xyImgCell.image = UIImage(named: tableImagesTwo[row])
}
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
println("cell \(indexPath.section) : \(indexPath.row) selected")
}
}

UICollectionView not working using swift without storyboard

I am trying to set up UICollectionView in my view controller. I am created custom cell CVCell.xib. My collection view is not showing up at all. What's missing in my code?
In my viewController.swift file:
#IBOutlet var collectionViewNew: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
self.collectionViewNew?.registerNib(UINib(nibName: "CVCell", bundle: nil), forCellWithReuseIdentifier: "CVCell")
}
func numberOfSectionsInCollectionView(
collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return 6
}
func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CVCell", forIndexPath: indexPath) as CVCell
cell.backgroundColor = UIColor.orangeColor()
return cell
}

Resources