I set a cell in the collectionView selected programmatically :
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(with: FAFavouriteCategoryCell.self, for: indexPath)!
let currentCategory = categories[indexPath.row]
cell.isSelected = selectedCategories.contains(currentCategory.categoryID)
cell.configCell(category: currentCategory)
return cell
}
after this all selected cells not working. I can't click on It.
If I clicked method shouldDeselectItemAt not calling
You need to call selectItem like this
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(with: FAFavouriteCategoryCell.self, for: indexPath)!
let currentCategory = categories[indexPath.row]
if selectedCategories.contains(currentCategory.categoryID) {
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .left) //Add this line
cell.isSelected = true
} else {
collectionView.deselectItem(at: indexPath, animated: false)
cell.isSelected = false
}
cell.configCell(category: currentCategory)
return cell
}
Related
So im trying to filter my collectionview data using another collectionview, something like this
as from the picture on i try to make a filter button so i can filter the data base on the button that user tap, and the way im trying to make that filter button is to use another collectionview, but i dont know how to implement it.
so far here's my code :
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == homeColView {
return homeVm.heroList.count
}else if collectionView == filterColView {
return homeVm.filterRoles.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == homeColView{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCollectionCell", for: indexPath) as! HomeCollectionCell
let data = homeVm.heroList[indexPath.row]
let imgUrl = URL(string: BASE_URL + data.img)
cell.heroNameLabel.text = data.localized_name
cell.heroImage.kf.setImage(with: imgUrl)
return cell
}else if collectionView == filterColView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FilterCollectionCell", for: indexPath) as! FilterCollectionCell
cell.filterLabel.text = homeVm.filterRoles[indexPath.row]
return cell
}
return collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCollectionCell", for: indexPath) as! HomeCollectionCell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == homeColView {
let vc = HeroDetailsVc()
vc.heroDetailsVm.heroDetails = homeVm.heroList[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
collectionView.deselectItem(at: indexPath as IndexPath, animated: true)
}else if collectionView == filterColView {
}
}
can anyone help me how to make this filter with collectionview?
Thank you
Using UICollectionView to display calendar, I have made today's date selected by default and want to deselect that when any other date selected. Below is my code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CalenderCell", for: indexPath) as! CalenderCollectionViewCell
cell.lblDayName.text = arrCalendarDays[indexPath.item]
cell.lblDate.text = arrCalendarOnlyDate[indexPath.item]
if indexPath.item == 0 {
if !isTodayDate {
cell.isSelected = true
} else {
cell.isSelected = false
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
isTodayDate = true
// Tried below code but not working
/* collectionViewWeekCalendar.indexPathsForSelectedItems?
.forEach {
self.collectionViewWeekCalendar.deselectItem(at: $0, animated: false) }
*/
let selectedCell:UICollectionViewCell = collectionViewWeekCalendar.cellForItem(at: indexPath)!
selectedCell.isSelected = true
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let selectedCell:UICollectionViewCell = collectionViewWeekCalendar.cellForItem(at: indexPath as IndexPath)!
selectedCell.isSelected = false
}
Problem is that, when selecting any other date, today's selected date is not getting deselect. Please guide.
the hacky and easiest way (i think)
use selected index
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CalenderCell", for: indexPath) as! CalenderCollectionViewCell
cell.lblDayName.text = arrCalendarDays[indexPath.item]
cell.lblDate.text = arrCalendarOnlyDate[indexPath.item]
if sellectedIndex == indexPath {
cell.isSelected = true
} else {
cell.isSelected = false
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndex = indexPath
collectionView.reloadData()
}
and at the start,
set selectedIndex = today date Index
I'm currently working on a swift application. In one view controller I have a collectionView with horizontal scrolling. The collectionView is look like horizontal tabs with more tabs. So some collectionViewCell's are not visible at initial time.
What I need is I want to auto-scroll the collectionView to next cell(if collectionView has an invisible cell in the right) or to the previous cell(if it has an invisible cell in the left) when I select a collectionViewCell. I was using a cocoa pod(SwipeMenuViewController), but it is making some issue with the presentation. Please help me to implement the same with collectionView.
Please see the image for more clarity.
This is my code,
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.tabArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "tabCell", for: indexPath) as! tabCollectionViewCell
cell.tabLabel.text = self.tabArray[indexPath.row]
if selectedTabArray.contains(indexPath) {
cell.bottomView.isHidden = false
} else {
cell.bottomView.isHidden = true
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.selectedTabArray.removeAll()
selectedTabArray.append(indexPath)
self.tabCollectionView.reloadData()
tabCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
You can just scroll to that indexPath on didSelectItemAt Method
var selectedIndex = 0
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "tabCell", for: indexPath) as! tabCollectionViewCell
cell.tabLabel.text = self.tabArray[indexPath.item]
if self.selectedIndex == indexpath.item {
cell.bottomView.isHidden = false
} else {
cell.bottomView.isHidden = true
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.selectedIndex = indexpath.item
self.tabCollectionView.reloadData()
tabCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
Hope this Help!
You can use the didSelectRowAt method to get the indexPath of the selected cell. then check if the cell is not the last cell. If it is not, scroll to right, else scroll to left.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
collectionView.reloadItems(at: [indexPath])
}
UPDATE1:
I didn't see the image when answering the question as it was not added yet. I have update my answer.
UPDATE2:
In your viewDidLoad,
collectionView.allowsMultipleSelection = false // in your view didLoad
then use property observers to change the selected index.
var selectedIndexPath : IndexPath = IndexPath(item: 0, section: 0) {
didSet {
self.collectionView.reloadItems(at: [selectedIndexPath])
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.tabArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "tabCell", for: indexPath) as! tabCollectionViewCell
cell.tabLabel.text = self.tabArray[indexPath.row]
cell.bottomView.isHidden = (indexPath == selectedIndexPath) ? false : true
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndexPath = indexPath
tabCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! tabCollectionViewCell
cell.bottomView.isHidden = true
}
var selectedIndex = 0
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "tabCell", for: indexPath) as! tabCollectionViewCell
cell.tabLabel.text = self.tabArray[indexPath.item]
if self.selectedIndex == indexpath.item {
cell.bottomView.isHidden = false
} else {
cell.bottomView.isHidden = true
}
return cell
}
Replace collectionView didSelectItemAt with following method to solve selection issue and reload collectionview,
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.selectedIndex = indexpath.item
UIView.animate(withDuration: 0, animations: {
tabCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}) { (_) in
self.tabCollectionView.reloadData()
}
}
I have a variabel selectedIndexPath, which gets the indexPath selected from previous view controller. I am getting the required backgroundColor for cell in the collection view of present view controller. But when I select another cell in the collection view, the selected cell of previous view controller remains same without being deselected. So, now I have two cells with the background color. Following is my code
var selectedIndexPath = IndexPath()
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.allowsMultipleSelection = false
self.collectionView.allowsSelection = true
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! TestCollectionViewCell
if (indexPath == selectedIndexPath)
{
cell.backgroundColor = UIColor.white
}
else
{
cell.backgroundColor = UIColor.clear
}
collectionView.allowsMultipleSelection = false
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = UIColor.white
collectionView.allowsMultipleSelection = false
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath)
{
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = UIColor.clear
collectionView.allowsMultipleSelection = false
}
How do I deselect the cell in cellForItemAt, when I select new cell in didSelectItemAt. Thanks in advance.
First of all set allowsMultipleSelection in Interface Builder and remove all redundant occurrences of setting it in code
You have to update the selectedIndexPath variable. Manipulating the cell directly is always a bad idea.
Reloading the cells is much more reliable.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
guard selectedIndexPath != indexPath else { return }
let indexPathsToUpdate = [selectedIndexPath, indexPath]
selectedIndexPath = indexPath
tableView.reloadRows(at: indexPathsToUpdate, with: .none)
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath)
{
guard selectedIndexPath == indexPath else { return }
selectedIndexPath = IndexPath()
tableView.reloadRows(at: [indexPath], with: .none)
}
There is only one problem: If you want to have an empty selection you have to declare selectedIndexPath as optional and handle it properly.
First of all, you don't need to override didDeselect for this. All you need to do is deselect the previously selected item while selecting the current item in didSelectItem. For that you can choose to maintain states in the cell as:
func changeToSelectedState() {
self.backgroundColor = UIColor.white
}
func changeToUnselectedState() {
self.backgroundColor = UIColor.clear
}
Or you can choose to write the same in the controller itself. And then you need to perform the deselection and selection in the following manner.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
let previousSelectedCell = collectionView.cellForItem(at: selectedIndexPath)
previousSelectedCell.changeToUnselectedState()
let currentCell = collectionView.cellForItem(at: indexPath)
currentCell.changeToSelectedState()
selectedIndexPath = indexPath
}
I have a collection view where users can select multiple cells and send the array of index to a server for saving their selection.
everything is working except that when the collection view is created the selected items needs to be clicked two times in order to deselect them.
How can I solve this issue of double clicking ?
extension ThirdViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return categoryList.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! UserCategoryCollectionViewCell
cell.categoryLbl.text = categoryList[indexPath.row]
if Defaults.hasKey(.categoryListIndices) {
if (Defaults[.categoryListIndices]?.contains(indexPath.row))! {
cell.alpha = 0.1
cell.isSelected = true
} else {
cell.alpha = 1
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! UserCategoryCollectionViewCell
cell.alpha = 0.1
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let deselectedCell = collectionView.cellForItem(at: indexPath) as? UserCategoryCollectionViewCell
deselectedCell?.alpha = 1
print(deselectedCell?.isSelected)
collectionView.deselectItem(at: indexPath, animated: false)
}
}
first of all. add this to your viewDidLoad.
collectionView?.allowsMultipleSelection = true
and then add these two functions.
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell=collectionView.cellForItem(at: indexPath)
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])
cell?.backgroundColor = Color.hexStringToUIColor(hex: "#F5A331")
let lbl = cell?.subviews[1] as! UILabel
lbl.textColor = Style.cellHighlightedColor
}
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
let cell=collectionView.cellForItem(at: indexPath)
collectionView.deselectItem(at: indexPath, animated: true)
cell?.backgroundColor = UIColor.white
let lbl = cell?.subviews[1] as! UILabel
lbl.textColor = UIColor.darkGray
}
This will do