I have the following UICollectionView which is populated by an Array with NSManagedObject of type Categories
The problem is that when a Cell is selected scrolling does not function correctly. When scrolling through the UICollectionView other cells get selected, and deselected. Strange behaviour. I think this is because of the indexPath that is set incorrectly after scrolling? Anyway, I have been struggling with this for a couple of hours, and cannot seem to grasp it. Hopefully someone can point me in the right direction!
The fetchedCategory gets compared to the category to check if it is already selected and if they are the same the colors are inverted.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("CategorySelectionCollectionCell", forIndexPath: indexPath) as CategoryCollectionViewCell
if fetchedCategories[indexPath.row] == category {
cell.categoryLabel?.text = fetchedCategories[indexPath.row].name
cell.categoryLabel?.textColor = UIColor.whiteColor()
cell.backgroundColor = fetchedCategories[indexPath.row].iconColor as? UIColor
collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: UICollectionViewScrollPosition.None)
} else {
cell.categoryLabel?.text = fetchedCategories[indexPath.row].name
cell.categoryLabel?.textColor = fetchedCategories[indexPath.row].iconColor as UIColor
collectionView.deselectItemAtIndexPath(indexPath, animated: true)
}
return cell
}
func collectionView(collectionView: UICollectionView!, didSelectItemAtIndexPath indexPath: NSIndexPath!) {
var cell = collectionView.cellForItemAtIndexPath(indexPath) as CategoryCollectionViewCell
cell.categoryLabel?.textColor = UIColor.whiteColor()
cell.backgroundColor = fetchedCategories[indexPath.row].iconColor as? UIColor
category = fetchedCategories[indexPath.row]
}
func collectionView(collectionView: UICollectionView!, didDeselectItemAtIndexPath indexPath: NSIndexPath!) {
if var cell = collectionView.cellForItemAtIndexPath(indexPath) as? CategoryCollectionViewCell {
cell.categoryLabel?.text = fetchedCategories[indexPath.row].name
cell.categoryLabel?.textColor = fetchedCategories[indexPath.row].iconColor as UIColor
cell.backgroundColor = UIColor.whiteColor()
}
}
You don't want to call cellForItemAtIndexPath and configure the cells in the didSelectItemAtIndexPath or didDeselectItemAtIndexPath delegate methods.
Also, you shouldn't be calling selectItemAtIndexPath and deselectItemAtIndexPath from within the cellForItemAtIndexPath method.
Instead, just keep track and toggle the state of the selected category in your select/deselect callbacks, and then don't do anything other the set up up the look of your cells in cellForItemAtIndexPath.
As the commenter pointed out, the cells are re-used, so stick to the simple way the delegate callbacks are designed to be used, and you should have much better luck.
If you need to refresh the look of the cells, do it by relying on cellForItemAtIndexPath being called while scrolling and using the reloadData and reloadItemsAtIndexPaths collection view methods if you need to force an update.
Related
When user choose a cell , I would like to get one of its specific UIViews and change its color.
So,
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
for cell in collectionView.visibleCells() as [UICollectionViewCell]
{
if(cell.tag==indexPath.row)
{
for view in [cell.contentView.subviews] {
view.backgroundColor=UIColor.redColor()
//here what ever I try I can't get it to see view as a UIView and change its properties, instead I get error that [UIView] has no member..
There's an easier way to do this. Simply get the cell you're interested in, and manipulate it directly. Using tags is a fragile method. Also, when you iterate through the subviews of another view, you're already dealing with an array, there's no need to wrap it in []s
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
for view in cell.contentView.subviews {
view.backgroundColor = UIColor.redColor()
}
}
This worked for me:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
var selectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
selectedCell.contentView.backgroundColor = UIColor.redColor()
}
If tableView is set in attribute inspector with selection to multiple Selection it should work. Just set it back in deselect:
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
{
var cellToDeSelect:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cellToDeSelect.contentView.backgroundColor = colorForCellUnselected
}
Your cell.contentView.subViews is in a array so view will turn out to be an array.
Loose the surrounding [] like this:
for view in cell.contentView.subviews {
view.backgroundColor=UIColor.redColor()
}
So I'm setting a UITableViewCell's layout programmatically when it is selected:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedCellIndexPath = indexPath
var selectedCell = tableView.cellForRowAtIndexPath(indexPath)!
tableView.beginUpdates()
tableView.endUpdates()
var cell:SelectedPatientCell = tableView.dequeueReusableCellWithIdentifier("patient selected", forIndexPath: indexPath) as! SelectedPatientCell
cell.patientName.text = patients[indexPath.row].fullName
cell.dob.text = patients[indexPath.row].dob
...
selectedCell = cell
}
And when I scroll the tableView, the layout of the cell resets to its original layout set in cellForRowAtIndexPath. However, the height stays as it should when I set it in the function above. Does anyone know how to fix this?
Here is an album of what's happening:
http://imgur.com/a/OUIMJ
Image 1:original state
Image 2: selected state (how it should stay on scrolling)
Image 3: what actually happens
you should hold this state in
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath == self.selectedCellIndexPath {
var cell:SelectedPatientCell = tableView.dequeueReusableCellWithIdentifier("patient selected", forIndexPath: indexPath) as! SelectedPatientCell
cell.patientName.text = patients[indexPath.row].fullName
cell.dob.text = patients[indexPath.row].dob
return cell
}
let cell = tableView.dequeueReusableCellWithIdentifier("patient selected") as! OriCell
...
return cell
}
in this way if you scroll tableView,it won't resume to original Cell.
Hopefully it is clear.
So I found my own solution:
Instead of doing
tableView.beginUpdates()
tableView.endUpdates()
I needed to do this at the end of the function:
tableView.reloadData()
and that solves the issue
I basically have a collection view where the cells have a view and that view's alpha decreases when the cell is tapped on. For some reason, when I scroll in the collection view, other cells views are also changing alphas and then the original cell that I selected also changed back. It has something to do with the cellForRowAtIndexPath method, but I'm not entirely sure what the issue is. Here is my code:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("chooseSpace", forIndexPath: indexPath)as! ChooseSpaceCell
let space = spaces2[indexPath.row]
cell.serviceLabel.text = spaces2[indexPath.row]
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! ChooseSpaceCell
cell.mask.alpha = 0.7
}
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! ChooseSpaceCell
cell.mask.alpha = 0.25
}
Originally, all the alphas start out at 0.25, change to 0.7 when tapped, and change back when deselected. This is a huge issue so any help would be much appreciated.
When you call
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("chooseSpace", forIndexPath: indexPath)as! ChooseSpaceCell
You are requesting a cell from the collection view. If there is a cell available it will reuse a cell that has already been created. If none are available it creates a new cell.
This means that when you scroll your collection view it is reusing the same cells that you used for previous items. If those items had there opacity changed the new items using that cell will have the same opacity.
You need to add an opacity field to your model or an attribute that will help you compute the opacity.
I have multiple UICollectionViewCells. When the user taps on a specific cell, I would like my app to change the background image of the touched cell.
My approach is to focus on the didSelectItemAtIndexPath method. When a cell is touched, this method will be called.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
var cell: UICollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("cellIdentifier", forIndexPath: indexPath) as! UICollectionViewCell
cell.backgroundView = UIImageView(image: UIImage(named: "myImage"))
}
However, I can't get it working but I don't know why. The issue is probably related to indexPath, that doesn't return a correct value of the cell. I tried using indexPath.row and this does actually return an Int number of the cell.
What's more, I'm also creating a new UICollectionViewCell with var but this cell already exists.
Why isn't the cell updating its background image? How do I change the background image of a UICollectionViewCell that has been touched by the user?
I totally agree with the Josh's answer, but if you change the background image using the didSelectItemAtIndexPath method it works fine as well. Then, you can use the cellForRowAtIndexPath method that returns the UITableViewCell at the specified indexPath, like in the following way:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!
cell.backgroundView = UIImageView(image: UIImage(named: "photo2"))
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
cell.backgroundView = UIImageView(image: UIImage(named: "photo1"))
cell.selectionStyle = .None
return cell
}
I just put the selectionStyle to .None to avoid the highlight. I hope this help you.
I'm having a problem with selected items in a collection view.
Selected items change backgroundColor to blue, but it seems like the reusable cells are also affected.
my code looks like this:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
var cell = collectionView.cellForItemAtIndexPath(indexPath) as UICollectionViewCell?
cell?.contentView.backgroundColor = UIColor.blueColor()
func collectionView(collectionView: UICollectionView, didDeslectItemAtIndexPath indexPath: NSIndexPath) {
var cell = collectionView.cellForItemAtIndexPath(indexPath) as UICollectionViewCell?
cell?.contentView.backgroundColor = UIColor.blackColor()
}
func collectionView(collectionView: UIControllerView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: boxCell = collectionView.dequeueReusableCellWithReuseIdentifier("demoCell", forIndexPath: indexPath) as boxCell
cell.cellTitle.text = name[indexPath.row]
}
When I run the application, the selection works, selecting another cell, deselects the other selected cells, but when I scroll, the reusable cells are also turning blue.
I am using a horizontal scroll direction with only 1 row and 4 cells per row.
Where did I go wrong? Anybody else have had this issue?
It's normal behavior - the reason for that is that the items are reused, and after reusing they go through cellForItemAtIndexPath where you are not setting background color, so they keep last one you ever set - in your case didSelect method.
You should create a NSSet where you will keep all selected NSIndexPath's and add / remove NSIndexPath to it when selecting / deselecting.
Setting background color logic should be done in cellForItemAtIndexPath - after you check if NSIndexPath is existing in your NSSet you set a desired color.
On selection you will have to also reload certain element, so it will call cellForItemAtIndexPath for the one you clicked.
Use the prepare for resue method in your cell class.It will work fine.
override func prepareForReuse()
{
self.backgroundColor = UIColor.lightGrayColor()
}