How to Set a specific Image to a specific array position? - ios

I am using a UICollectionView for Horizontal scrolling having six images in the array. What I want is when an item at index path x(1) is clicked an array with images to be set on remaining items(0,2,3,4,5) except position 1. Can we set a specific image at a specific position of an array if yes then how?
In the case of Android, it is like
if (selectedPosition < 0) {
viewHolder.imageView.setImageResource(coloredSmiley[position]);
} else {
viewHolder.imageView.setImageResource(selectedPosition == position ? coloredSmiley[position] : greySmiley[position]);
}
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var selectedImageButton = -1
var imagearray = ["AngrysmIcon1", "UpsetsmIcon2", "ConfusedsmIcon3", "MehsmIcon4", "CurioussmIcon5" , "HappysmIcon6"]
var bwimagearray = ["AngrysmIcon1Inactive", "UpsetsmIcon2Inactive", "ConfusedsmIcon3Inactive", "MehsmIcon4Inactive", "CurioussmIcon5Inactive", "HappysmIcon6Inactive"]
var positiontag = ["0", "1", "2", "3", "4", "5"]
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.positiontag.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! UIcollectionViewCellCollectionViewCell
cell.imagev.image = UIImage(named: imagearray[indexPath.row])
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
internal func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedImageButton = indexPath.row
let cell = collectionView.cellForItem(at: indexPath) as! UIcollectionViewCellCollectionViewCell
if selectedImageButton < 0 {
//cell.imagev.image = bwimagearray[indexPath.row]
} else {
cell.imagev.image = UIImage(named: imagearray[indexPath.row])
}
}
}
Where selectedposition is global with value -1

From the Android snippet, i believe you need to change cellForRowAt as below,
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! UIcollectionViewCellCollectionViewCell
let imageName: String
if selectedImageButton < 0 {
imageName = imagearray[indexPath.row]
} else {
imageName = selectedImageButton == indexPath.row ? imagearray[indexPath.row] : bwimagearray[indexPath.row]
}
cell.imagev.image = UIImage(named: imageName)
return cell
}
And then set the selectedImageButton in didSelectItemAt and reload the collectionView,
internal func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedImageButton = indexPath.row
collectionView.reloadData()
}
Note: ReloadData may not be recommended and you should look for some more reactive way to notify the cells to update image.

Add this to cellForItemAt
if cell.isSelected {
cell.imagev.image = UIImage(named: imagearray[indexPath.row])
} else {
cell.imagev.image = UIImage(named: bwimagearray[indexPath.row])
}
and following to didSelectItemAt
collectionView.reloadData()
But would recommend to move the logic that set all this to cell something like below mentioned
class UIcollectionViewCellCollectionViewCell: UICollectionViewCell {
override var isSelected: Bool {
get {
return super.isSelected
}
set {
super.isSelected = newValue
updateImage()
}
}
private func updateImage() {
if isSelected {
imagev.image = UIImage(named: imagearray[indexPath.row])
} else {
imagev.image = UIImage(named: bwimagearray[indexPath.row])
}
}
}

Related

In iOS Swift integrate Different array for CollectionView Inside TableView in Swift 4

How to set CollectionView data to Collection tag.collection tag count is not fixed .How to integarte cellForItemAt and numberOfItemsInSection in CollectionView .So I have a collectionView inside of a tableView. I would like to use the values from my array to populate each labels text inside each collectionViewCell. If I print the code below in collectionView cellForItemAt.
class testViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var providerCategoryTableView: UITableView!
let collectionReuseIdentifier = "selectServiceProviderCollectioncell" // Collection cell identifier in the storyboard
let tableReuseIdentifier = "selectServiceProviderTableViewCell"
var providerCategoryTableViewDictionary = [NSMutableDictionary]()
var providerCategoryCollectionViewDictionary = [String:Any]()
var providerCategoryDictionary = [[String:Any]]()
var ServiceResponse:[[String:Any]] = {[id:1,provider_name:”Telephone”,providers:[{category_name:”Test1”,id:”1”}, {category_name:”Test2”,id:”2”}]], [id:2,provider_name:”MobileNumber”,providers:[{category_name:”Test3”,id:”1”}, {category_name:”Test2”,id:”2”}, {category_name:”Test4”,id:”4”}, {category_name:”Test5”,id:”5”}]]}
var setIndexTag:Int = 0
var cellForItemIndexTag:Int = 0
var exapandTableViewArray = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
initControls()
}
// Expand function
func isExpandable(tableViewHeight:Int) -> Bool {
for item in exapandTableViewArray {
if(tableViewHeight == item){
return true
}
}
return false
}
// MARK: - Private
func initControls(){
providerCategoryTableView.tableFooterView = UIView()
callSelectServiceProvidersAPI()
addServiceProviderLabel.attributedText = GlobalFunctions().addNormalAndBoldText(normalText: NSLocalizedString("RecipientSelectServiceProvidersViewController.addServiceProviderNormalLabel", comment: ""), boldText: NSLocalizedString("RecipientSelectServiceProvidersViewController.addServiceProviderBoldLabel", comment: ""), fontSize : 16.0)
DontSeeYourServiceUILabel.attributedText = GlobalFunctions().addNormalAndBoldText(normalText: NSLocalizedString("RecipientSelectServiceProvidersViewController.DontSeeYourServiceUINormalLabel", comment: ""), boldText: NSLocalizedString("RecipientSelectServiceProvidersViewController.DontSeeYourServiceUIBoldLabel", comment: ""),fontSize : 16.0)
suggestAServiceUIView.layer.borderColor = UIColor( red: CGFloat(115/255.0), green: CGFloat(204/255.0), blue: CGFloat(215/255.0), alpha: CGFloat(1.0) ).cgColor
}
// MARK: - UITableView
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ServiceResponse.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: tableReuseIdentifier, for: indexPath) as! RecipientSelectServiceProviderTableViewCell
let providerCategoryObject = selectServiceProviderResponse[indexPath.row]
cell.categoryNameLabel.text = (providerCategoryObject["name"] as? String)!
cell.categoryCollectionView.delegate = self
cell.categoryCollectionView.dataSource = self
cell.categoryCollectionView.tag = indexPath.row
cell.categoryCollectionView.reloadData()
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if(isExpandable(tableViewHeight:indexPath.row)){
return 60
}else{
return 120
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath) as! RecipientSelectServiceProviderTableViewCell
let UpBlueImage = UIImage(named: "up_blue_arrow")
let UpBlueImageData = UIImagePNGRepresentation(UpBlueImage!)
let SelectedImageData = UIImagePNGRepresentation((selectedCell.UpDownImageView.image)!)
if (SelectedImageData == UpBlueImageData){
exapandTableViewArray.append(indexPath.row)
selectedCell.UpDownImageView.image = UIImage(named:"down_blue_arrow")
self.CategoryTableView.beginUpdates()
self.CategoryTableView.endUpdates()
}else{
if let index = exapandTableViewArray.index(of:indexPath.row) {
exapandTableViewArray.remove(at: index)
}
selectedCell.UpDownImageView.image = UIImage(named:"up_blue_arrow")
self.CategoryTableView.beginUpdates()
self.CategoryTableView.endUpdates()
}
}
// MARK: - UICollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//return collectioncategories.count
/* if collectionView.tag == 0{
return collectioncategories.count
}else if collectionView.tag == 1{
return collectionSecondcategories.count
}*/
for obj in ServiceResponse {
if collectionView.tag == setIndexTag {
let providers:[[String: Any]] = obj["providers"] as! [[String : Any]]
return providers.count
}
setIndexTag = setIndexTag + 1
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionReuseIdentifier, for: indexPath) as! RecipientSelectServiceProviderCollectionViewCell
//cell.categoryUILabel.text = collectioncategories[indexPath.row]
/*if collectionView.tag == 0{
cell.categoryUILabel.text = collectioncategories[indexPath.row]
}else if collectionView.tag == 1{
cell.categoryUILabel.text = collectionSecondcategories[indexPath.row]
}*/
for obj in ServiceResponse {
if collectionView.tag == cellForItemIndexTag {
let providers:[[String: Any]] = obj["providers"] as! [[String : Any]]
let data = providers[indexPath.row]
print("providers",providers[indexPath.row])
print("data",data)
for provider in providers {
print("cellForItemAt provider.name",provider["name"] as! String)
cell.categoryUILabel.text! = (provider["name"] as? String)!
print("cell.categoryUILabel.text",cell.categoryUILabel.text!)
}
}
cellForItemIndexTag = cellForItemIndexTag + 1
}
return cell
}
/* func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout,sizeForItemAt indexPath: IndexPath) -> CGSize {
let nbCol = 3
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left + flowLayout.sectionInset.right + (flowLayout.minimumInteritemSpacing * CGFloat(nbCol - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(nbCol))
return CGSize(width: size, height: size)
}*/
I want
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//return collectioncategories.count
if collectionView.tag == 0{
return collectioncategories.count
}else if collectionView.tag == 1{
return collectionSecondcategories.count
}
}
But 0,1....n collectionView.tag not fixed and inside array count also different.Please Its Urgent.Thanks
i have done a similar application where what we did is create one parent array
ie
var tableViewDataArray = [HomeDataHolder] () // which includes the type , sub category in my case myclass contains category name , category id and product array
after this add each category in to this array for me, added dataArry[banners,toppicks,.....]
this is how added class object to arraya
if let categoryes = JSON["categories"] as? NSArray{
for index in 0..<categoryes.count{
self.categoryArray.add(categoryes[index])
}
print(self.categoryArray)
self.session.saveCategory(self.categoryArray)
let catObject = HomeDataHolder(type:"CATEGORY").addCategoryes(categoryArray: self.categoryArray)
self.tableViewDataArray.append(catObject)
}
set tableview datasource as this array
if you need different type design design different cells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let homeData = tableViewDataArray[indexPath.row] as! HomeDataHolder
if homeData.type == "CATEGORY"{
let cell = tableView.dequeueReusableCell(withIdentifier: "category_name_cell", for: indexPath) as! HomeCategoryTableViewCell
cell.selectionStyle = .none
let dataArray = homeData.dataArray
cell.setProducArray(dataArray!)
cell.delegate = self
return cell
}else if .......
in my HomeCategoryTableViewCell class
func setProducArray(_ data:NSMutableArray){
for index in 0..<data.count{
dataArray.add(data[index])
}
colectionView.reloadData()
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "home_categoryes_cellection_cell", for: indexPath) as! HomeCategoriesCollectionViewCell
if let dataDictionary = dataArray[indexPath.row] as? NSDictionary{
utility.setCornerRadius([cell.containerView], cornerRadies: 19)
cell.categoryNameLabel.text = dataDictionary.getStringValue("name")
print(dataDictionary.getStringValue("name"))
}
return cell
}
and my HomeCategoryTableViewCell contains a collection view cell.setProducArray(dataArray!) will change the datasource of the collectionview
In your cellForRow of the TableView access the collectionView with viewWithTag and then give it the indexPath.row in the accessiblityHint property and call reload. Then in the your numberOfSections, numberOfItems or cellForItem methods of collectionView you can access the accessiblityHint property and access your array's index to display the data you want.

Two Collection Views in One View Controller iOS

I have two collection Views in One View Controller, First Collection View have class CollectionCellA with imageA as UIImageView! and labelA as UILabel!. Similarly Second Collection View with class CollectionCellB with imageB and labelB. I tried to run with following swift code but it show just blank(white) screen.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var imageArroy = [UIImage(named: "1"), UIImage(named: "2"), UIImage(named: "3"), UIImage(named: "5"), UIImage(named: "6")]
var imageArroyB = [UIImage(named: "a"), UIImage(named: "b"), UIImage(named: "c"), UIImage(named: "d"), UIImage(named: "e")]
var labelA: ["Electronics", "Cars", "Pets", "Mobiles", "Food"]
var labelB: ["UK", "Ireland", "India", "Germany", "Other EU"]
#IBOutlet weak var CollectionViewA: UICollectionView!
#IBOutlet weak var CollectionViewB: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
CollectionViewA.delegate = self
CollectionViewB.delegate = self
CollectionViewA.dataSource = self
CollectionViewB.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.CollectionViewA {
return 0 // Replace with count of your data for collectionViewA
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.CollectionViewA {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellA", for: indexPath) as! CollectionCellA
// Set up cell
return cellA
}
else {
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellB", for: indexPath) as! CollectionCellB
// ...Set up cell
return cellB
}
}
This code works for Two Collection View in One View Controller with images and label.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.CollectionViewA {
return imageArroy.count
}
return imageArroyB.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.CollectionViewA {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellA", for: indexPath) as! CollectionCellA
cellA.imageA.image = imageArroyB[indexPath.row]
cellA.labelA.text = labelA[indexPath.row]
// Set up cell
return cellA
}
else {
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellB", for: indexPath) as! CollectionCellB
cellB.imageB.image = imageArroyB[indexPath.row]
cellB.labelB.text = labelB[indexPath.row]
// ...Set up cell
return cellB
}
}
For me below code works like a charm . you should send/assign value in cellForItemAt indexPath
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.CollectionViewA {
return imageArroy.count
}
return imageArroyB.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.CollectionViewA {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellA", for: indexPath) as! CollectionCellA
// Set up cell
cellA.lbl.text = labelA[indexPath.row]
return cellA
}
else {
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellB", for: indexPath) as! CollectionCellB
// ...Set up cell
cellB.lbl.text = labelB[indexPath.row]
return cellB
}
}
}
class CollectionCellA : UICollectionViewCell {
#IBOutlet weak var lbl: UILabel!
}
class CollectionCellB : UICollectionViewCell {
#IBOutlet weak var lbl: UILabel!
}
Add two collection view and connect delegate and data source with view countroller,create collection view cell and connect with cell and outlets
#IBOutlet weak var collectionView2: UICollectionView!
#IBOutlet weak var collectionview1: UICollectionView!
var days = ["Sun","Mon","Tues","Wed","Thur","Frid","Sat"]
var dayTask = [String]()
var task = [["Sun1","Mon1","Tues1","Wed1","Thur1","Frid1","Sat1"],["Sun2","Mon2","Tue2","Wed2"],["Sun3","Mon3","Tues3","Wed3","Thur3","Frid3","Sat3"],["Sun4","Mon4"],["Sun5","Mon5","Tues5","Wed5","Thur5","Frid5","Sat5"],["Sun6","Mon6","Tues6","Wed6"],["Sun7","Mon7","Tues7","Wed7","Thur7"]]
override func viewDidLoad() {
super.viewDidLoad()
dayTask = task[0]
// Do any additional setup after loading the view.
}
Collection view data source and delgate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == collectionview1{
return days.count
}else{
return dayTask.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell1", for: indexPath) as! CollectionViewCell1
if collectionView == collectionview1{
cell.label.text = days[indexPath.row]
let collectionViewLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
collectionViewLayout?.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 40)
collectionViewLayout?.invalidateLayout()
}else
{
let collectionViewLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
collectionViewLayout?.sectionInset = UIEdgeInsets(top: 10, left: 20, bottom: 0, right: 40)
collectionViewLayout?.invalidateLayout()
cell.label.text = dayTask[indexPath.row]
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == collectionview1{
dayTask = task[indexPath.row]
collectionView2.reloadData()
}
}

CollectionView issue - Swift

I make music player using collectionView. I want to when selected collectionView like radio button. If another cell is selected, the selected cell should not be selected. but is not working.
I dont want multi selection. : https://i.stack.imgur.com/ATj3J.png
How do I work? TT I need your help. thx.
this my code.
import UIKit
class PracticeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var homeClassInPrac = HomeViewController()
var songPlayOff = UIImage(named: "play")
var songPlayOn = UIImage(named: "iconStop")
var buttonCounter = [Int]()
var freqNameList = ["Delta 1","Theta 1","Alpha 1","Beta 1","Delta 2","Theta 2","Alpha 2","Beta 2","Delta 3","Theta 3","Alpha 3","Beta 3","Delta 4","Theta 4","Alpha 4","Beta 4"]
#IBOutlet var practiceCollection: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
practiceCollection.delegate = self
practiceCollection.dataSource = self
self.practiceCollection.allowsMultipleSelection = false
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
self.practiceCollection.reloadData()
return freqNameList.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:PracticeCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "pracCell", for: indexPath) as! PracticeCollectionViewCell
cell.pracImgView.image = songPlayOff
cell.pracLabel.text = freqNameList[indexPath.row]
if buttonCounter.contains(indexPath.row){
cell.pracImgView.image = songPlayOn
}
else{
cell.pracImgView.image = songPlayOff
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if buttonCounter.contains(indexPath.row){
let index = buttonCounter.index(of: indexPath.row)
buttonCounter.remove(at: index!)
self.practiceCollection.reloadData()
homeClassInPrac.audioPlayer2.stop()
}
else{
buttonCounter.removeAll()
buttonCounter.append(indexPath.row)
self.practiceCollection.reloadData()
let buttonInt = buttonCounter[0]
homeClassInPrac.playSound2(freqName: freqNameList[buttonInt])
}
print("Select\(buttonCounter)")
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
print("Deselect\(buttonCounter)")
let index = buttonCounter.index(of: indexPath.row)
buttonCounter.remove(at: index!)
self.practiceCollection.reloadData()
print("Deselect\(buttonCounter)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
I think problem is you are reloading collectionView in numberOfItems method
so Just remove
self.practiceCollection.reloadData()
Change buttonCounter to Array of Bool with equal count to freqNameList
var buttonCounter : Array<Bool> = [false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false]
In cellForItem method use :
if buttonCounter[indexPath.row]{
cell.pracImgView.image = songPlayOn
}
else{
cell.pracImgView.image = songPlayOff
}
In didSelectItem use :
buttonCounter[indexPath.row] = true
homeClassInPrac.playSound2(freqName: freqNameList[buttonInt])
self.practiceCollection.reloadData()
In didDeselectItem use :
buttonCounter[indexPath.row] = false
self.practiceCollection.reloadData()

Adding new Item to CollectionView programmatically, via the last Item

I'm facing an issue with CollectionView, I want to see a collection of images and have an add button as the last item so first of all I've made an array of NSData as I'm gonna save those images to Core Data
var photoArray = [NSData]()
then I implement UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == photoArray.count + 1 {
present(imagePicker, animated: true, completion: nil)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photoArray.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoItem", for: indexPath) as? PhotoCell else {return UICollectionViewCell()}
cell.btn.tag = indexPath.item
if indexPath.item == photoArray.count + 1 {
cell.thumImage.image = UIImage(named: "add_button")
cell.btn.isHidden = true
print("first")
return cell
} else {
let img = photoArray[indexPath.item]
cell.configureAddingImage(img: img)
print("second")
return cell
}
}
Actually I'm facing with the problem in "cellForItemAt indexPath" like "fatal error: index is out of range" I tried to make array look like var photoArray: [NSData]! but it caused other problems, please give me any advice or help, thank you!
Index is out of range because items or rows are indexed from 0
Should be like this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoItem", for: indexPath) as? PhotoCell else {return UICollectionViewCell()}
cell.btn.tag = indexPath.row
if indexPath.row == photoArray.count {
cell.thumImage.image = UIImage(named: "add_button")
cell.btn.isHidden = true
print("first")
return cell
} else {
let img = photoArray[indexPath.row]
cell.configureAddingImage(img: img)
print("second")
return cell
}
}

UICollectionView - Select all cells doesn't update properly

I have a button which selects all cells in the collectionview. Once clicked, the button function changes so that all cells will be de-selected upon pressing it again.
So far so good.. But
1) When you select all cells with the button, scroll a bit down and to the top again
2) Then de-select all cells with the button, and select all cells with the button again
3) And start scrolling down, some cells (mostly 1-2 complete rows, later cells are fine again) are not properly updated, so they don't appear with the selected state which is a different background color. Seems like an issue with dequeueReusableCell, but I can't wrap my head around it..
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if cell.isSelected {
cell.backgroundColor = UIColor.green
} else {
cell.backgroundColor = UIColor.white
}
if cell.viewWithTag(1) != nil {
let cellTitle = cell.viewWithTag(1) as! UILabel
cellTitle.text = String(indexPath.row)
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
cell.backgroundColor = UIColor.green
selectedCells.append(indexPath.row)
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
cell.backgroundColor = UIColor.white
selectedCells.removeObject(indexPath.row)
}
}
And the action method for handling button clicking
#IBAction func selectButtonTapped(_ sender: Any) {
if isSelectAllActive {
// Deselect all cells
selectedCells.removeAll()
for indexPath: IndexPath in collectionView!.indexPathsForSelectedItems! {
collectionView!.deselectItem(at: indexPath, animated: false)
collectionView(collectionView!, didDeselectItemAt: indexPath)
let cell: UICollectionViewCell
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCell", for: indexPath)
}
selectButton.title = "Select all"
isSelectAllActive = false
} else {
// Select all cells
for i in 0 ..< collectionView!.numberOfItems(inSection: 0) {
collectionView!.selectItem(at: IndexPath(item: i, section: 0), animated: false, scrollPosition: UICollectionViewScrollPosition())
collectionView(collectionView!, didSelectItemAt: IndexPath(item: i, section: 0))
}
selectedCells.removeAll()
let indexPaths: [IndexPath] = collectionView.indexPathsForSelectedItems!
for item in indexPaths {
selectedCells.append(item.row)
}
selectedCells.sort{$0 < $1}
selectButton.title = "Select none"
isSelectAllActive = true
}
}
And for completion the array extension for removing an object
extension Array where Element : Equatable {
mutating func removeObject(_ object : Iterator.Element) {
if let index = self.index(of: object) {
self.remove(at: index)
}
}
}
Complete Xcode project can be found here: https://www.dropbox.com/s/uaj1asg43z7bl2a/SelectAllCells.zip
Used Xcode 9.0 beta 1, with iOS11 Simulator/iPhone SE
Thanks for your help!
Your code is a little confused because you are trying to keep track of cell selection state both in an array and in the cell itself.
I would just use a Set<IndexPath> as it is simpler and more efficient than an array. You can then refer to this set when returning a cell in cellForItemAt: and you don't need to do anything in willDisplay.
When you select/deselect all you can just reload the whole collection view and when an individual cell is selected/deselected, just reload that cell.
#objcMembers
class MainViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet var collectionView: UICollectionView!
#IBOutlet var toolBar: UIToolbar?
#IBOutlet weak var selectButton: UIBarButtonItem!
var selectedCells = Set<IndexPath>()
var isSelectAllActive = false
// MARK: - Classes
override func viewDidLoad() {
super.viewDidLoad()
// Collection view
collectionView!.delegate = self
collectionView!.dataSource = self
collectionView!.allowsMultipleSelection = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
#IBAction func selectButtonTapped(_ sender: Any) {
if isSelectAllActive {
// Deselect all cells
selectedCells.removeAll()
selectButton.title = "Select all"
isSelectAllActive = false
} else {
// Select all cells
for i in 0 ..< collectionView!.numberOfItems(inSection: 0) {
self.selectedCells.insert(IndexPath(item:i, section:0))
}
selectButton.title = "Select none"
isSelectAllActive = true
}
self.collectionView.reloadData()
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 50
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: UICollectionViewCell
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCell", for: indexPath)
if self.selectedCells.contains(indexPath) {
cell.backgroundColor = .green
} else {
cell.backgroundColor = .white
}
if cell.viewWithTag(1) != nil {
let cellTitle = cell.viewWithTag(1) as! UILabel
cellTitle.text = String(indexPath.row)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("\ndidSelectItemAt: \(indexPath.row)")
if selectedCells.contains(indexPath) {
selectedCells.remove(indexPath)
} else {
selectedCells.insert(indexPath)
}
self.collectionView.deselectItem(at: indexPath, animated: false)
self.collectionView.reloadItems(at: [indexPath])
print("selectedCells: \(selectedCells)")
}
}

Resources