CollectionView scrolling changes the selected cells - ios

CollectionView scrolling changes the selected cells. For example, there are 26 letters in my collectionView, items[0] is A, items[1] is B, ... items[25] is Z, now I selected items[1], it is B, and when I scroll the collectionView, items[1] will become deselected and there is another item will be selected. I know the problem is caused by Reuse but I don't know how to fix it properly even I use some solution that showed in google or StackOverflow.
My viewDidLoad:
collectionView.allowsMultipleSelection = false
My CollectionViewCell Class:
import UIKit
class AddCollectionViewCell: UICollectionViewCell {
}
My CollectionView Setting:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return iconSet.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "iconCell", for: indexPath) as! IconCollectionViewCell
cell.iconImage.image = UIImage(named:iconSet[indexPath.row])
return cell
}
My CollectionView's didSelecteItemAt function:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
cell.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.3)
cell.backgroundView?.layer.cornerRadius = 5
}
My CollectionView's didDeSelecteItemAt function:
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
cell.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.0)
cell.backgroundView?.layer.cornerRadius = 5
}
}

You can achieve this by either store all selected item's index in separate array or you can manage separate property like isSelected in dictionary or array of custom class's objects whichever you used to fill your collectionview cells.
You can simply use array like below:
var arrIndex : [Int] = Int
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "iconCell", for: indexPath) as! IconCollectionViewCell
cell.iconImage.image = UIImage(named:iconSet[indexPath.row])
if arrIndex.contains(indexPath.item) {
cell.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.3)
}
else {
cell.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.0)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if !arrIndex.contains(indexPath.item) {
arrIndex.append(indexPath.item)
collectionview.reloadData()
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if arrIndex.contains(indexPath.item) {
arrIndex = arrIndex.filter { $0 != indexPath.item }
collectionview.reloadData()
}
}

You can try
var selectedIndex = 0 // set default or nil and check it's nullability before usage
//
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "iconCell", for: indexPath) as! IconCollectionViewCell
cell.iconImage.image = UIImage(named:iconSet[indexPath.row])
if indexPath.row == selectedIndex {
cell.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.3)
}
else {
cell.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.0)
}
return cell
}
My CollectionView's didSelecteItemAt function:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndex = indexPath.row
collectionview.reloadData()
}
My CollectionView's didDeSelecteItemAt function:
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
// remove this
}

Related

How to display UICollectionView inside static TableViewCell?

I want to display UICollectionView inside static TableViewCell
I have a static TableViewCell that contains CollectionView. Well, the problem is that, in my opinion, code looks good but when I launch program, TableViewCell doesn't show me CollectionView. I'm a little bit confused, so I will be so happy if you help me. Thanks
TableViewController Class:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var Cell = tableView.dequeueReusableCell(withIdentifier: "Action")
switch indexPath.section {
case 0:
tableView.register(ScheduleCell.self, forCellReuseIdentifier: "Schedule")
Cell = tableView.dequeueReusableCell(withIdentifier: "Schedule") as! ScheduleCell
case 1:
return Cell!
case 2:
tableView.register(MarksCell.self, forCellReuseIdentifier: "Marks")
Cell = tableView.dequeueReusableCell(withIdentifier: "Marks") as! MarksCell
default:
Cell = tableView.dequeueReusableCell(withIdentifier: "Action") as! ActionCell
}
return Cell!
}
ActionCell:
extension ActionCell: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ActionCell", for: indexPath) as! ActionsCollectionViewCell
var Labels = ["РАСПИСАНИЕ", "ДОМАШНИЕ ЗАДАНИЯ", "ОЦЕНКИ"]
var Icons = ["Safari", "DZ", "Rating"]
var Colors = [UIColor.init(red: 26/255, green: 196/255, blue: 234/255, alpha: 1),
UIColor.init(red: 251/255, green: 143/255, blue: 25/255, alpha: 1),
UIColor.init(red: 251/255, green: 25/255, blue: 118/255, alpha: 1)]
cell.Title.text = Labels[indexPath.item]
cell.Icon.image = UIImage.init(named: Icons[indexPath.item])
cell.Button.backgroundColor = Colors[indexPath.item]
return cell
}
}
Also, I have to notice that in Storyboard i mentioned all classes and ReuseIDs
If you're using 'UITableView' with Static Cells as a content you don't need to implement 'tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)' everything can be defined in Storyboard.
Here's how the UITableViewController would look like in storyboard, using custom cells (TableCell, CollectionCell) both for table and collection view, and having 'UITableViewCell'
act as a data source for containing 'UICollectionView':
And here's UITableViewController implementation:
class ViewController: UITableViewController {
}
class TableCell: UITableViewCell {
}
class CollectionCell: UICollectionViewCell {
}
extension TableCell: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
}

After reload collectionview,it always move to the first cell if also select the last cell

I have attached this image. You can see the problem here I have implemented the horizontal collection view where cells contains label. When we select the not visible items of the cell (after the first load 4 to 5 items are visible) and reload the cell it always moves to first visible cells.how should I handle the this problem?
func collectionView(
_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
"profile_CollectionViewCell_city", for: indexPath as IndexPath) as!
profile_CollectionViewCell
cell.contentView.translatesAutoresizingMaskIntoConstraints = false
if ((self.data_array[indexPath.row] as! NSMutableDictionary)["title"] != nil) {
cell.city_name.text = ((self.data_array[indexPath.row] as! NSMutableDictionary)["title"] as? String)?.uppercased()
}
if (indexPath.row == selectedIndex) {
cell.city_name.textColor = UIColor(red: (0.0 / 255.0), green: (120.0 / 255.0), blue: (56.0 / 255.0), alpha: 1)
cell.city_name.font = UIFont(name: "Poppins-Bold", size: 14)
cell.lower_view.isHidden = false
} else {
cell.city_name.textColor = UIColor(red: (156.0 / 255.0), green: (156.0 / 255.0), blue: (156.0 / 255.0), alpha: 1)
cell.city_name.font = UIFont(name: "Poppins-Light", size: 14)
cell.lower_view.isHidden = true
}
return cell
}
func collectionView(
_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return data_array.count
}
func collectionView(
_ collectionView: UICollectionView,
layoutCollectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath: IndexPath) -> CGSize {
let size = ((self.data_array[indexPath.row] as!
NSMutableDictionary)["title"] as? String)?.size(withAttributes:
nil) ?? CGSize.zero
return size
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAtIndexPath: IndexPath) {
selectedIndex = indexPath.row
self.city_table.reloadData()
}

Selecting a Cell inside UICollectionView in a custom keyboard

I have a Cell comprising of an Image View inside a UI Collection View in a custom keyboard extension. Everything looks good except when I try to select an item in the collection view nothing happens. Any idea/suggestions?
Yes, I have attached delegates.
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.delegate = self
self.collectionView.dataSource = self
self.collectionView.allowsSelection = true
self.collectionView.allowsMultipleSelection = false
}
//This works
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "cell",for: indexPath)
cell.backgroundColor = #colorLiteral(red: 0, green: 0.4117647059, blue: 0.8509803922, alpha: 1)
return cell
}
//This doesnt
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "cell",for: indexPath)
cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
}
Any idea/Suggestions?
EDIT:
Uploaded my code to github for better suggestions :)

UICollectionview Reuse Existing cell

I want to generate collectionview with 100 number of cells, But it should not to be reallocate at every time of scrolling, But in my code its always creating cells newly.
any one help me to avoid this issue, please find my code below,
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return colorArray.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let colleCell: colorCell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! colorCell
colleCell.bgColor.backgroundColor = UIColor(red: colorArray[indexPath.row].valueForKey("Red") as! CGFloat/255, green: colorArray[indexPath.row].valueForKey("Green") as! CGFloat/255, blue: colorArray[indexPath.row].valueForKey("Blue") as! CGFloat/255, alpha: 1.0)
return colleCell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
let cell:colorCell = collectionView.cellForItemAtIndexPath(indexPath) as! colorCell
cell.layer.borderWidth = 2.0
cell.layer.borderColor = UIColor.whiteColor().CGColor
selectedColor = indexPath.row
sampleColorView.backgroundColor = UIColor(red: colorArray[indexPath.row].valueForKey("Red") as! CGFloat/255, green: colorArray[indexPath.row].valueForKey("Green") as! CGFloat/255, blue: colorArray[indexPath.row].valueForKey("Blue") as! CGFloat/255, alpha: 1.0)
self.view.backgroundColor = UIColor(red: colorArray[indexPath.row].valueForKey("Red") as! CGFloat/255, green: colorArray[indexPath.row].valueForKey("Green") as! CGFloat/255, blue: colorArray[indexPath.row].valueForKey("Blue") as! CGFloat/255, alpha: 0.7)
sampleColorView.layer.cornerRadius = 75
}
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath)
{
let cell:colorCell = collectionView.cellForItemAtIndexPath(indexPath) as! colorCell
selectedIndex = -1;
cell.layer.borderWidth = 0.0
cell.layer.borderColor = UIColor.grayColor().CGColor
self.view.backgroundColor = UIColor.grayColor()
}
I think it's reused correctly, plz double check? But I suggest the way to set selected/deselected cell's style, you can override selected property of UICollectionViewCell.
class ColorCell : UICollectionViewCell{
override var selected: Bool{
didSet {
layer.borderWidth = selected ? 2 : 0
layer.borderColor = selected ? UIColor.whiteColor().CGColor : UIColor.grayColor().CGColor
}
/* your code */
}
and UICollectionViewDelegate implementation:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
selectedColor = indexPath.row
sampleColorView.backgroundColor = /*Color*/
view.backgroundColor = /*Color*/
sampleColorView.layer.cornerRadius = 75
}
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
selectedIndex = -1;
self.view.backgroundColor = UIColor.grayColor()
}

UICollectionView and selected UICollectionViewCell

I'm trying to do a simple UICollectionView with a custom cell composed of an UIImageView and an UIView above.
When a cell is not selected, the UIView on the top of the cell have is backgroundColor property set to UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).
I have issues with the selection. The collectionView:didSelectItemAtIndexPath: method is called but when I change the UIView described previously, nothing happen.
Here is the code of my collectionView :
class TestCollectionViewController: UICollectionViewController
{
var items = [1, 2, 3]
let cellId = "Cell"
override func viewDidLoad()
{
self.collectionView.allowsMultipleSelection = true
self.collectionView.delaysContentTouches = false
}
override func collectionView(collectionView: UICollectionView!, numberOfItemsInSection section: Int) -> Int
{
return items.count
}
override func collectionView(collectionView: UICollectionView!, cellForItemAtIndexPath indexPath: NSIndexPath!) -> UICollectionViewCell!
{
var cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellId,
forIndexPath: indexPath) as TestingCollectionViewCell
let item = items[indexPath.row]
cell.imageView.image = UIImage(named: "img")
cell.overlayView.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.5)
return cell
}
override func collectionView(collectionView: UICollectionView!, didSelectItemAtIndexPath indexPath: NSIndexPath!)
{
var cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellId,
forIndexPath: indexPath) as TestingCollectionViewCell
cell.overlayView.backgroundColor = UIColor.clearColor()
}
override func collectionView(collectionView: UICollectionView!, didDeselectItemAtIndexPath indexPath: NSIndexPath!)
{
var cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellId,
forIndexPath: indexPath) as TestingCollectionViewCell
cell.overlayView.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.5)
}
}
If this snippet is not enough, here is my project
You should not be dequeuing a new cell in didSelectItemAtIndexPath (or in didDeselect either) -- this is creating (or reusing) a new cell, not getting the one you selected. Use this instead,
var cell = collectionView.cellForItemAtIndexPath(indexPath)
To me the following code worked better (the code of rdelmar crashed sometimes, which might be a bug? in Swift):
(collectionView.cellForItemAtIndexPath(indexPath) as myCollectionViewCellType).uiBackground?.backgroundColor = UIColor.blackColor()
Edit: I forgot to mention: My collectionView-Items are based on their own class to which I cast. uiBackground is an element of that class
Swift 3.0
let cell = collectionView.cellForItem(at: indexPath)
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
//saving index path of the image loaded from imageproperty_array
selected_imagepath = imageproperty_array[indexPath.row] as String
//saving index of the selected cell item as Int
selected_imageindex = indexPath.row
}

Resources