I have a UICollectionView within a View Controller. When the cell is clicked it updates the image associated with the cell. However, when a cell isSelected and then scrolled out of view and another cell is selected, it appears as the isSelected == true image until it is brought out and back into view once more. Images below hopefully describe the action better.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CustomCollectionViewCell
// Configure the cell
cell.layoutIfNeeded()
if cell.isSelected {
let image = imageArray1[indexPath.row]
cell.cellImage.image = image
return cell
} else {
let image = imageArray2[indexPath.row]
cell.cellImage.image = image
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? CustomCollectionViewCell else {
return
}
// deselect unused
cell.isSelected = false
cell.cellImage.image = imageArray2[indexPath.row]
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! CustomCollectionViewCell
cell?.isSelected = true
cell.cellImage.image = imageArray1[indexPath.row]
}
Step 1: First cell is selected and changes to red image.
Step 2: Selected first cell is out of view and 5th cell is now selected, which should make cell 1 turn back to grey image.
Step 3: first cell should be unselected but when it is brought back into view it is still showing as selected. It will change back to grey image if it goes out and back into view once more.
Related
How can I save the selected state of UICollectionView inside an UITableViewCell?
For more details, I have an UITableView with 5 sections and each section has only 1 cell, I put another UICollectionView into the cell of the table view and whenever I select an item of collection view cell it will highlight with a red background.
Now I wanna save the selection state for the collection view even if I dismiss the view controller then open it again it must display the correct selected item and I think I will use UserDefaults for saving. But I noticed that when I select an item of collection view in another section it always saves the same index with the first section of the table view.
Here is my code for saving the selected index path to an array, can you please tell me where's my mistake:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let strData = itemFilter[indexPath.section].value[indexPath.item]
let cell = collectionView.cellForItem(at: indexPath) as? SDFilterCollectionCell
cell?.filterSelectionComponent?.bind(title: strData.option_name!, style: .select)
cell?.backgroundColor = .red
cell?.layer.borderColor = UIColor.white.cgColor
arrSelectedIndex.append(indexPath)
}
and when deselect:
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let strData = itemFilter[indexPath.section].value[indexPath.item]
let cell = collectionView.cellForItem(at: indexPath) as? SDFilterCollectionCell
cell?.filterSelectionComponent?.bind(title: strData.option_name!, style: .unselect)
cell?.backgroundColor = .white
cell?.layer.borderColor = UIColor.black.cgColor
if arrSelectedIndex.count > 0 {
arrSelectedIndex = arrSelectedIndex.filter({$0 != indexPath})
}else {
arrSelectedIndex.removeAll()
}
}
As you mention you want to save arrSelectedIndex in userdefault, so get arrSelectedIndex from userdefault.
if you have collectionView in each section of UITableView then with arrSelectedIndex save the indexpath of table section as well.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.cellForItem(at: indexPath) as? SDFilterCollectionCell else {
return UICollectionViewCell()
}
// color the background accordingly
if arrSelectedIndex.contains(indexPath) {
// selected state
cell.backgroundColor = .red
} else {
// non-selected state
cell.backgroundColor = .white
}
cell.layer.borderColor = UIColor.white.cgColor
return cell
}
I created a collectionView and want to set the cell section background color
since I do not know how many rows it have and I do not want to set background color in other sections
set the whole cell section backgroundcolor
You can do it on your cellForItemAt, hope this helps :)
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SampleCell
if indexPath.section == 1 {
cell.backgroundColor = UIColor.systemPink
} else {
cell.backgroundColor = UIColor.white
}
return cell
}
You can do it with following code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! TestCell
if indexPath.section == 1 {
cell.backgroundColor = UIColor.red
} else {
cell.backgroundColor = UIColor.orange
}
return cell
}
finally I find the solution.
In the cell there is two UIView that is cell View and contentView. And all views you add is in the contentView. So I should:
set the cell background color
add a layer which frame is inseted by the cell frame
set the layer background color
add views
please bear with me as I am new to swift programming.
I have a myCollectionViewController that is a subclass of UICollectionViewController. The cells for the MyCollectionViewController are a class of MyCollectionViewCell, which is a custom UICollectionViewCell.
What I am trying to do is change the background of the MyCollectionViewCell based on the user selection AND have this selection persist when the user scrolls to other cells of the MyCollectionViewController. I have tried two ways to do this, and so far both have failed.
The first way was to write code in the didSelectItemAt method of the MyCollectionViewController:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath) as! MyCollectionViewCell
cell.contentView.backgroundColor = UIColor.red
}
However, this did not work and the cell colour was not changed.
The other way I tried to do this was by changing the isSelected property of the MyCollectionViewCell.
override var isSelected: Bool {
// Change what happens when the user selects a cell
didSet {
if self.isSelected {
self.contentView.backgroundColor = Colours.primary
} else {
self.contentView.backgroundColor = Colours.secondary
}
}
}
Although this worked, the selection did not persist. That is when the user scrolled to a different cell in the collectionView and then scrolled back, the selection was gone.
Any advice would be appreciated.
Don't use dequeue in didSelectItemAt as it'll return other cell than the clicked
var allInde = [IndexPath]()
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at:indexPath) as! MyCollectionViewCell
cell.contentView.backgroundColor = UIColor.red
if !(allIndex.contains(indexPath)) {
allInde.append(indexPath)
}
}
and in cellForItem check whether indexpath to show is in the array and color it
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "id", for: indexPath as IndexPath) as! MyCollectionViewCell
if allIndex.contains(indexPath) {
cell.contentView.backgroundColor = Colours.primary
}
else {
cell.contentView.backgroundColor = Colours.secondary
}
}
// se here updated code
SPRAIN
I am modally presenting a viewcontroller that hosts a viewcollection with "pre-selected" cells formatted to a different background color based on data passed on segue.
When I tap on one of these "pre-selected" cells, it takes two taps to trigger the didDeselectItemAt delegate method. I understand why this is happening while debugging, where the cell although of different color is not necessarily recognized in a selected state. Is there any way to trigger didDeselectItemAt first for the "pre-selected" cells?
I've tried, within the delegate method cellForItemAt, to incorporate, as part of a conditional statement that changes the cell background color, setting cell.isSelected = true. Similarly within the same delegate method, I've also tried invoking a function that would invoke the delegate method didSelectItemAt with indexPaths of these "pre-selected" cells. Both produced the same result.
Below is (abbreviated) relevant code snippets:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! ExampleCollectionViewCell
if preselectedDataPoints { cell.backgroundColor = blue }
else { cell.backgroundColor = white }
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = blue
preselectedDataPoints.append(newDataPoint)
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = white
preselectedDataPoints.remove(at: existingDataPoint)
}
Programatically call collectionView.deselectItem(at: indexPath, animated: true) in didSelectItem if cell is preselected.
Refrer code
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if preselectedDataPoints {
collectionView.deselectItem(at: indexPath, animated: true)
}else{
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = blue
preselectedDataPoints.append(newDataPoint)
}
}
or
Directly call what ever code you need to execute in deSelect method
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if preselectedDataPoints {
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = white
preselectedDataPoints.remove(at: existingDataPoint)
}else{
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = blue
preselectedDataPoints.append(newDataPoint)
}
}
Im using UIcollection view as my tabbar
when I scroll collection view horizontally previous selected cell will not deselect when i select new one
this is my code to change colour when i select a cell and deselect a cell
var selectedIndexPath : IndexPath = []
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as?
BottomCollectionViewCell {
cell.contentView.backgroundColor = UIColor.orange
cell.backgroundColor = UIColor.orange
}
if let preViousSelectedcell = collectionView.cellForItem(at:
selectedIndexPath) as? BottomCollectionViewCell {
preViousSelectedcell.contentView.backgroundColor=UIColor.purple
preViousSelectedcell.backgroundColor = UIColor.purple
}
selectedIndexPath = indexPath
}
while scrolling cells are reused that time cellForItemAt will call so you need to change some modification in your code
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
selectedIndexPath = indexPath
YOUR_COLLECTION_VIEW.reloadData()
}
and add below lines inside your collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
if indexPath == selectedIndexPath {
cell.contentView.backgroundColor=UIColor.purple
cell.backgroundColor = UIColor.purple
} else {
cell.contentView.backgroundColor = UIColor.orange
cell.backgroundColor = UIColor.orange
}
Hope this will help you