Changing text color in UICollectionView in Swift - ios

I have a UICollectionView with cells that contain UILabels that update dynamically. When I select a cell, I have the background color of the cell change, but I want the text color in the label to change as well. Currently, I'm using the following code:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
cell = collectionView.dequeueReusableCellWithReuseIdentifier("targetCell", forIndexPath: indexPath) as UICollectionViewCell
var label : UILabel = cell.viewWithTag(100) as UILabel
label.textColor = UIColor.whiteColor()
}
However, on selecting the cell, the text color does not update with the new color. Any ideas why?

Because you are dequeuing a reusable cell and update it.
Basically, dequeueReusableCellWithReuseIdentifier:forIndexPath: is only used in collectionView:cellForItemAtIndexPath:.
Use cellForItemAtIndexPath to get the selected cell.
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
let label = cell.viewWithTag(100) as? UILabel
label?.textColor = UIColor.white
}
}

Related

UICollectionView - random cells are selected

I have a Horizontal UICollectionView like the horizontal Calender in iOS.
Paging is enabled but not allowsMultipleSelection.
self.allowsMultipleSelection = false
self.isPagingEnabled = true
There are only 5 cells per page.
let cellSize = CGSize(width: self.view.frame.width / 5 , height: 60)
CollectionView's height is also 60.
didSelectItemAt change background color to .red and didDeselectItem resets it to .white.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
if let cell = cell {
cell.backgroundColor = .red
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
if let cell = cell {
cell.backgroundColor = .white
}
}
The collection view has multiple sections and rows. If I select a cell in the first visible page and scroll, random cells are selected in the next visible pages. That is to say random cells are red in the next pages. I do not want this to be so. I want to select/change color of cells manually.
How can I fix this?
Don't forget that UICollectionView has embedded reusing mechanism, so you should deselect your cells in the method "prepareToReuse" directly inside the cell class.
Take a class-level variable, say index
var index = -1
As you have said that multiple selections are not allowed so the following will do the job for you
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
index = indexPath.item
collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
if let cell = cell {
cell.backgroundColor = indexPath.item == index ? .red : .white
}
}
Whenever user tap on any cell we save the position in index variable and then call the reloadData() to notify collectionView about the change
In cellForRowAt we check if the current cell us selected we set the color to red otherwise white
First, if you want to preserve multiple selection, you have to remember your selected ones in an array since it would get lost if a cell gets recycled and reused. For that use something like a [IndexPath] type). If one selected cell is enough, you could use a non-array version of below code.
var selectedItems: [IndexPath] = []
Then, do your recoloring in your cell's cellForItemAt(:):
cell.backgroundColor = selectedItems.contains(indexPath) ? .red : .white
Your didSelectItemAt delegate function should look like:
if !selectedItems.contains(indexPath) { selectedItems.append(indexPath)}
collectionView.cellForItem(at: indexPath)?.backgroundColor = .red
and your didDeselectItemAt delegate function:
if let index = selectedItems.firstIndex(of: indexPath) { selectedItems.remove(at: index) }
collectionView.cellForItem(at: indexPath)?.backgroundColor = .white
This should actually work. Let me know if we have to do adjustments.

UIcollectionView weird cell recycling behaviour

I have a UICollectionView with flow layout, about 140 cells each with a simple UITextView. When a cell is recycled, I pop the textView onto a cache and reuse it later on a new cell. All works well until I reach the bottom and scroll back up. At that point I can see that the CollectionView vends cell number 85, but then before cell 85 is displayed it recycles it again for cell 87 so I now lose the content of the cell I had just prepared.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FormCell", for: indexPath) as! FormCollectionViewCell
let textView = Cache.vendTextView()
textView.text = "\(indexPath.row)"
cell.addSubview(textView)
cell.textView = textView
return cell
}
And on the UIcollectionViewCelC
override func prepareForReuse() {
super.prepareForRuse()
self.textView.removeFromSuperView()
Cache.returnView(self.textView)
}
I would have thought that after cellForItemAtIndexPath() was called, it would then be removed from the reusable pool of cells but it seems it is immediately being recycled again for a neighbouring cell. maybe a bug or I am possibly misunderstanding the normal behaviour of UICollectionView?
As I understand it, what you're trying to do is just keep track of cell content - save it when cell disappears and restore it when it comes back again. What you're doing can't work well for couple of reasons:
vendTextView and returnView don't take indexPath as parameter - your cache is storing something and fetching something, but you have no way of knowing you're storing/fetching it for a correct cell
There's no point in caching the whole text view - why not just cache the text?
Try something like that:
Have your FormCollectionViewCell just have the text view as subview, and modify your code like so:
class YourViewController : UIViewController, UICollectionViewDataSource, UICollectionViewDelegate
{
var texts = [IndexPath : String]()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FormCell", for: indexPath)
if let formCell = cell as? FormCollectionViewCell {
cell.textView.text = texts[indexPath]
return cell
}
}
func collectionView(_ collectionView: UICollectionView,
didEndDisplaying cell: UICollectionViewCell,
forItemAt indexPath: IndexPath)
{
if let formCell = cell as? FormCollectionViewCell {
{
texts[indexPath] = formCell.textView.text
}
}
}

UICollectionView: Random Cell highlighted

I have a collectionview with various cells. One can be selected at once and the selection state is stored inside my business logic. If a cell is selected the whole section get's reloaded to update the UI to highlight the currently selected cell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
...
cell.setItemSelected(selected: selected)
return cell
}
My problem is that a random cell get's highlighted to for a short time.
I also implemented prepareForReuse() but without any effect.
What can cause this?
Thanks!
Here the requested additional code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let pendencyDeficiencyType = deficiencyTypes[indexPath.row]
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PendencyDetailCell.reuseIdentifier, for: indexPath) as? PendencyDetailCell{
cell.titleLabel.attributedText = StringUtils.hyphenedText(pendencyDeficiencyType.rawValue)
cell.indexPath = indexPath
cell.delegate = self
let selected = pendencyDeficiencyType == pendencyItem?.pendencyDeficiencyType
cell.setItemSelected(selected: selected)
return cell
}
return collectionView.dequeueReusableCell(withReuseIdentifier: PendencyDetailCell.reuseIdentifier, for: indexPath)
}
override func prepareForReuse() {
super.prepareForReuse()
backgroundColor = Styling.cellDefaultColor
titleLabel.textColor = .black
}
func setItemSelected(selected: Bool){
layer.borderColor = selected ? Styling.heagPrimary.cgColor : UIColor.darkGray.cgColor
backgroundColor = selected ? Styling.cellSelectedColor : Styling.cellDefaultColor
titleLabel.textColor = selected ? .white : .black
}
As an option you can implement two separate cells.. one for each state and use it depending on the flag.
OR
Try to use different ReuseIdentifiers depending on the flag.

How to remove custom view from invisible cell in collection view

I am trying to change color of selected custom view in collection view. I am using didSelectItem and didDeselectItem method of collection view for the same.
I am facing error when i am going to change invisible cell in collectionview.
Visible cell of collection view is perfectly working
My code is below
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = colCellSize.cellForItem(at: indexPath) as! colSizeDetails
cell.viewDetails.backgroundColor = UIColor.gray
cell.lblSize.textColor = UIColor.white
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = colCellSize.cellForItem(at: indexPath) as! colSizeDetails
cell.viewDetails.layer.borderWidth = 2.0
cell.viewDetails.layer.borderColor = UIColor.gray.cgColor
cell.lblSize.textColor = UIColor.gray
cell.viewDetails.backgroundColor = UIColor.white
}
This line is wrong:
let cell = colCellSize.cellForItem(at: indexPath) as! colSizeDetails
Here, you are casting the cell as a colSizeDetails. The colSizeDetails should be it's own class with a subclass of UICollectionViewCell. Your class names should never start with a lowercase letter. You need to change your class name to ColSizeDetails and then re-write that line with the capital letter. This may be the issue as I cannot see you force unwrapping anymore optionals

UICollectionView Cells not shown if UITabBarController is on second tab Swift

I have a weird issue with UICollectionView and UITabBarController. Inside the UITabBarController i have references to two different ViewControllers. If i put View Controller that has UICollectionView as a first page of UITabBarController then my list with cells (UICollectionView) is loading normally like this:
But if i put it as a second View Controller when i open the tab it is like UIImageView and UILabel are disappearing from the cells:
I have checked collectionView method that is getting the cells and there is always data printed for the Label and Image. Here is a code of the methods for DataSource and Delagate
// tell the collection view how many cells to make
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.items.count
}
// make a cell for each cell index path
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! AdsCollectionViewCell
// Use the outlet in our custom class to get a reference to the UILabel in the cell
cell.myLabel.text = self.items[indexPath.item]
cell.backgroundColor = UIColor.whiteColor() // make cell more visible in our
cell.layer.borderColor = UIColor.grayColor().CGColor
cell.layer.borderWidth = 1
cell.layer.cornerRadius = 8
cell.layoutIfNeeded()
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let width = collectionView.frame.width - 22;
return CGSize(width: width/2, height: width/2);
}
// MARK: - UICollectionViewDelegate protocol
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
// handle tap events
print("You selected cell #\(indexPath.item)!")
}
Is there someone that had problem like this? How can it be solved?

Resources