I have a UICollectionView and there user can select on cell to use the Function in it. So and i need it to set the first cell to selected like in the First Screenshot. But the Problem there is when the cell is selected and user want to select ah other cell the first cell don´t unselect. I have try it to reload the tableview in did select item but that don´t run or with this func in viewdidload LabelCollectionView.selectItem(at: IndexPath(row: 1, section: 0), animated: true, scrollPosition: .bottom)
Have anyone an idea what i can make there ? thanks for Help:)
First Cell Selected
Here you see the Problem in the screenshot
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "StoryLabelCell", for: indexPath) as! StoryLabelCell
let labels = Labels[indexPath.row]
cell.backgroundColor = UIColor.lightGray
cell.layer.cornerRadius = 10
cell.Title.text = labels
if indexPath.row == 0 {
cell.backgroundColor = darkgrau
cell.layer.borderColor = black.cgColor
cell.layer.borderWidth = 2.0
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! StoryLabelCell
if indexPath.row == indexPath.row {
cell.backgroundColor = darkgrau
cell.layer.borderColor = black.cgColor
cell.layer.borderWidth = 2.0
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! StoryLabelCell
if indexPath.row == indexPath.row {
cell.backgroundColor = lightGray
cell.layer.borderWidth = 0
}
}
What are you trying to do with checking for indexPath.row == indexPath.row? Basically you can try with cell.selected = true when it is selected and set it to false when deselected. Try below code and let me know if it works.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "StoryLabelCell", for: indexPath) as! StoryLabelCell
let labels = Labels[indexPath.row]
cell.backgroundColor = UIColor.lightGray
cell.layer.cornerRadius = 10
cell.Title.text = labels
if indexPath.row == 0 {
cell.backgroundColor = darkgrau
cell.layer.borderColor = black.cgColor
cell.layer.borderWidth = 2.0
cell.selected = true
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! StoryLabelCell
cell.backgroundColor = darkgrau
cell.layer.borderColor = black.cgColor
cell.layer.borderWidth = 2.0
cell.selected = true
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! StoryLabelCell
cell.backgroundColor = lightGray
cell.layer.borderWidth = 0
cell.selected = false
}
u should use the Cells selected state instead of comparing two values that are the same.
In you custom cell you react on cell selections!
override func setSelected(_ selected: Bool, animated: Bool) {
// change your cell like you want
if selected {
// make me dark
} else {
// make me light
}
// not tested, but somehow call the super
super.setSelected(selected:selected, animated: animated)
}
you can delete your didSelect and didDeselct func.
In the function cellForItem ... you can check if a cell is selected, if not select the one with indexPath.row == 0
For checking a selected cell use
collectionView.indexPathForSelectedItems
this is list, so you can select more than one cell. I am not sure, but i think u can setup the collectionView with multiple selections ore only one selection.
I hope this helps you so far.
Related
when I select one item in a collection view, another item further down gets selected. Can someone tell me how to fix this?
Here's my code:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as? Category3Cell {
cell.contentView.backgroundColor = #colorLiteral(red: 1, green: 0.8674157229, blue: 0.4739984274, alpha: 1)
recommends.append(cell.categoryKey)
print("select \(recommends)")
cell.isSelected = true
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as? Category3Cell {
cell.contentView.backgroundColor = .clear
recommends = recommends.filter(){$0 != cell.categoryKey}
print("deselect \(recommends)")
cell.isSelected = false
}
}
Cells are being reused when you scroll.
You must therefore make sure to reset things like background color in your func cellForItem(at indexPath: IndexPath).
I have in my swift app two collection views. One which is a functions categories and another one which is the functions. The first one works as a filter to the second one. If I select "Cat1" then only functions with tag "Cat1" are displayed. This works great.
The functions categories collectionview is horizontal and I need to scroll to see all the cells. My issue/problem is already mentioned in another topics but I can not find the right anwser or technique.
Issue: If I select a category, the cell's background changes, fine. If now I scroll completely to the end of the collectionview and select the last cell, this one change as selected the the first one (previously selected) is not deselected.. I know that is a problem with reused cell but no idea how to manage that. Below my code :
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// Working with functions categories collection view
if collectionView == self.functionsCategoriesCollectionView {
let cell = collectionView.cellForItem(at: indexPath) as! DevicePageFunctionsCategoriesCVCell
cell.isHidden = false
cell.cellView.isHidden = false
cell.isSelected = true
cell.cellView.clipsToBounds = true
cell.cellView.layer.cornerRadius = 25
cell.cellView.addGradiant(colors: [UIColor(red: 127.0/255.0, green: 127.0/255.0, blue: 127.0/255.0, alpha: 1.0).cgColor, UIColor(red: 47.0/255.0, green: 47.0/255.0, blue: 47.0/255.0, alpha: 1.0).cgColor], angle: 45)
if cellSelectionIndexPath == indexPath {
// it was already selected
cellSelectionIndexPath = nil
collectionView.deselectItem(at: indexPath, animated: true)
cell.cellView.addGradiant(colors: [UIColor.clear.cgColor, UIColor.clear.cgColor], angle: 0)
self.filtered = GlobalVariables.currentProduct.functions.filter { _ in
return true
}
self.functionsCollectionView.reloadData()
} else {
// wasn't yet selected, so let's remember it
cellSelectionIndexPath = indexPath
// Filter with seletec category name
let cellCategoryName = ICDatabase.objects(FunctionCategory.self)[indexPath.row]
self.filtered = GlobalVariables.currentProduct.functions.filter { function in
return function.functionCategory.contains(cellCategoryName)
}
self.functionsCollectionView.reloadData()
}
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if collectionView == self.functionsCategoriesCollectionView {
if let cellToDeselect = collectionView.cellForItem(at: self.cellSelectionIndexPath) as? DevicePageFunctionsCategoriesCVCell {
cellToDeselect.isSelected = false
collectionView.deselectItem(at: self.cellSelectionIndexPath, animated: true)
cellToDeselect.cellView.addGradiant(colors: [UIColor.clear.cgColor, UIColor.clear.cgColor], angle: 0)
self.cellSelectionIndexPath = nil
// Get all functions
self.filtered = GlobalVariables.currentProduct.functions.filter { _ in
return true
}
self.functionsCollectionView.reloadData()
}
}
}
Thanks for your help!
Try this -
var selectedIndexPath: IndexPath?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell.layer.backgroundColor = UIColor.black
self.selectedIndexPath = indexPath
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell.layer.backgroundColor = UIColor.white
self.selectedIndexPath = nil
}
Collection cells reuse memory. So you have to manually manage data and UI. If your requirement is to select only one category cell in collection view at any time, keep one variable in collection view and update it in didSelect method.
var selectedIndexPath: IndexPath?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndexPath = indexPath
collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = UICollectionCell()
....
cell.backgroundColor = UIColor.black
if indexPath == selectedIndexPath {
cell.backgroundColor = UIColor.red
}
}
I have a tableView and collectionView in one view controller.
in tableView I have title description and in collectionView I have lable .
I want on collectionView label selection tableView content should change .
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Bookmark.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionViewBookmark.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BookMarkCollectionViewCell
cell.lblTitle.text = Bookmark[indexPath.row]
cell.backgroundColor = UIColor.white
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionViewBookmark.cellForItem(at: indexPath)
cell?.backgroundColor = UIColor.blue
self.selectedIndexPath = indexPath
//
let newsDict = arrNewsData[indexPath.row]
if (indexPath.row == 1)
{
let cell1 = tableViewBookMark.cellForRow(at: indexPath) as! BookMarkFirstTableViewCell
cell1.lblTitle.text = newsDict["title"] as! String
tableViewBookMark.reloadData()
}
tableViewBookMark.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableViewBookMark.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! BookMarkFirstTableViewCell
let dict = arrNewsData[indexPath.row]
cell.lblTitle.text = dict["title"] as! String
// cell.imgBookMark.image = dict["image_url"]
let url = URL(string: dict["image_url"] as! String)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if data != nil{
DispatchQueue.main.async {
let image = UIImage(data: data!)
cell.imgBookMark.image = image
}
}
}.resume()
return cell
}
See my inline comments.
var tempCell: BookMarkFirstTableViewCell?
//Inside cellForRowAt indexPath
tempCell = cell
//Inside (collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
tempCell.lblTitle.text = newsDict["title"] as! String
You're reloading the tableView after updating the values in the cell,
tableViewBookMark.reloadData()
This will trigger the data source function including cellForRowAt, so you will lose your updated values a solution to this is to have a global variable in the UIViewController and check its values inside the cellForRowAt and update it in the collectionView DidSelect .
Extra tip: you don't need to reload all the tableView for a single change you can use
tableView.reloadRows(at: [indexPath], with: .top)
to reload only number of selected cells in the tableView
I am new to swift and trying to implement collectionView function in a ViewController.Now I have three types of UICollectionViewCell,here is my code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionViewCategory {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: categoryIdentifier, for: indexPath as IndexPath) as! CategoryCell
cell.CategoryIcon.image = self.categoryItems[indexPath.item]
cell.layer.borderColor = UIColor.lightGray.cgColor
cell.layer.borderWidth = 1
cell.layer.cornerRadius = 5
return cell
}
else if collectionView == self.collectionViewHour {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: hourIdentifier, for: indexPath as IndexPath) as! HourCell
cell.hourItem.text = self.hourItems[indexPath.item]
cell.layer.borderColor = UIColor.lightGray.cgColor
cell.layer.borderWidth = 1
cell.layer.cornerRadius = 5
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: minuteIdentifier, for: indexPath as IndexPath) as! MinuteCell
cell.minuteItem.text = self.minuteItems[indexPath.item]
cell.layer.borderColor = UIColor.lightGray.cgColor
cell.layer.borderWidth = 1
cell.layer.cornerRadius = 5
return cell
}
}
Can I use switch statement to achieve the same effect?Make the code look a little more elegant?
I hope my code looks like this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:UICollectionViewCell
switch collectionView {
case self.collectionViewCategory:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: categoryIdentifier, for: indexPath as IndexPath) as! CategoryCell
cell.CategoryIcon.image = self.categoryItems[indexPath.item]
case self.collectionViewHour:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: hourIdentifier, for: indexPath as IndexPath) as! HourCell
cell.hourItem.text = self.hourItems[indexPath.item]
default:
//do nothing.
}
cell.layer.borderColor = UIColor.lightGray.cgColor
cell.layer.borderWidth = 1
cell.layer.cornerRadius = 5
return cell
}
But I got a lot of mistakes, and I do not know how to fix them.
You can try to assign each collectionView a unique tag like so
collectionView.tag = 1
and then use the tag as the identifier:
switch collectionView.tag {
case 0:
// some code
case 1:
// some code
default:
// some code
}
If you're using your collectionViews inside UITableViewCells you can set each collectionView.tag to be indexPath.section or indexPath.row within tableView(_ tableView: willDisplay cell: forRowAt indexPath:).
Here's a nice subclass you could use:
class CollectionViewTableViewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
func setCollectionViewDataSourceDelegate(dataSource: UICollectionViewDataSource?, dataDelegate: UICollectionViewDelegate?, forSection section: Int) {
collectionView.delegate = dataSource as! UICollectionViewDelegate?
collectionView.dataSource = dataDelegate as! UICollectionViewDataSource?
collectionView.tag = section
collectionView.reloadData()
}
}
and then in your view controller implement
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? CollectionViewTableViewCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(dataSource: self, dataDelegate: self, forSection: indexPath.section)
}
Hope this help. Not testing at all. If any issues, can you take a snip ?
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:UICollectionViewCell
switch collectionView {
case self.collectionViewCategory:
let categoryCell = collectionView.dequeueReusableCell(withReuseIdentifier: categoryIdentifier, for: indexPath as IndexPath) as! CategoryCell
categoryCell.CategoryIcon.image = self.categoryItems[indexPath.item]
cell = categoryCell
case self.collectionViewHour:
let hourCell = collectionView.dequeueReusableCell(withReuseIdentifier: hourIdentifier, for: indexPath as IndexPath) as! HourCell
hourCell.hourItem.text = self.hourItems[indexPath.item]
cell = hourCell
default:
//do nothing.
}
cell.layer.borderColor = UIColor.lightGray.cgColor
cell.layer.borderWidth = 1
cell.layer.cornerRadius = 5
return cell
}
Hi I have two codes for someone reason 1 works while the other doesn't can someone please explain why? The first function works, while the second doesn't. I'm trying to generate one cell as the type PayNowCell and every cell after that as the CheckOutCell type. However, it will only allow me to put the first cell as a CheckOutCell, the second as a PayNowCell, and every following cell as a CheckOutCell. Thanks!!! Error is index is out of bounds. And it points to this line
cell.item = checkout[indexPath.item].
Essentially i have a dynamic array checkout[] and im just trying to insert a description cell called paynow ontop of each checkoutcell while the checkout[] grows and shrinks
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "paynow", for: indexPath) as! PayNowCell //init cells
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CheckoutCell //init cells
cell.item = checkout[indexPath.item]
return cell
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "paynow", for: indexPath) as! PayNowCell //init cells
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CheckoutCell //init cells
cell.item = checkout[indexPath.item]
return cell
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (checkout.count + 1) //init number of cells
}
Try this array for manage your collection view
var array = [0,[]]
then add
array[1] = [your array for index 1]
You can add the section for manage multi-cell inside your collection view:-
func numberOfSections(in collectionView: UICollectionView) -> Int{
return (array[section] as AnyObject).count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return array[1].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "paynow", for: indexPath) as! PayNowCell //init cells
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CheckoutCell //init cells
let checkout = array[1] // pass here array
guard checkout.count != 0 else {
return cell
}
cell.item = checkout[indexPath.item]
return cell
}
}