I am new to iOS developing and I am using Swift 3.
In my gallery app when user selects a cell, the picture inside that cell displays in a UIImageView above and the cell itself becomes bordered red to show that it is selected right now. However, when I scroll up or down and as soon as the selected cell is destroyed UICollectionView selects another cell from the visible ones.
I want to know how can I restore the selected state of a cell when it reused and prevent UICollectionView from doing that. In conclusion I want to know how to prevent from cell reusabilities effects on selection state.
Sorry for my bad English, not a native speaker.
you can either have an array of the images states if it's true then it's selected else it's not and in the
collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
function you check on the state and do the required setup for the cell or you can make the collection view don't reuse the cells by changing the cell identifier dynamically like this
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCircularCollectionViewCell\(indexPath.row)", for: indexPath) as? HomeCircularCollectionViewCell
//setup cell
return cell
}
hope my answer helps you in your problem
Related
How can I display an another image on selection of an Collection View Cell ImageView in an swift language of IOS example.
I hope it will help you,
override func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
// here you know which item is selected by accessing indexPath.item property, for example: and then reload only selected cell
}
Thanks
I've been successfully nesting collections views into tableview for a while now.
What I still don't know how to do, is to do it while respecting the MVC pattern?
Right now I declare my tableview and its cells and in the cell (where the collectionView sits), I attach my collectionView (I got 1 per cell) and do the data mapping. It works, but it's spaghetti code where my View is acting like a controller.
I tried a few times to respect the MVC patterns. I can get my controller to control both my tableview and my collection. Where I struggle is to tell my collection View delegate which data it should pick as all I have as reference is the indexPath (of the collectionView) but not in which tableView that specific collectionView sits.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
return cell
}
The delegate only gives me the indexPath of the cell not which collectionView it is. To use a concrete example - let's assume that my tableview cells represents messages and that each message has a collectionView that controls reactions (like Discord). How do I tell my collectionView delegate which Message it is linked to?
Thanks a lot for the help!
This is very simple. Every view and its subclass has a property tag. You must have an IBOutlet or a simple reference to the CollectionView that sits in the TableViewCell. When you dequeue the TableViewCell just set the tag of your CollectionView equal to the indexPath.row of your tableViewCell like this:
tableViewCell.collectionView.tag = indexPath.row
Then in the UICollectionViewDataSource or UICollectionViewDelegate methods you may find which collectionView it is in other words which tableViewCell does this collectionView sits in. Here's an example:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
let dataObject = dataSourceArray[indexPath.row] as! YourDataModelObject
// Here you may set any property of the collectionView cell
return cell
}
P.S: It is not necessary to respect MVC to that extent. You may manage your CollectionView from the TableViewCell. Have a look at this example.
I'm using a collection view and every time I select the cell I change the cell background color to red. Simple enough:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)! as! CustomCell
cell.backgroundColor = .red
}
This works absolutely fine. When I select the top 3 cells going from left to right, the background color changes exactly as I expect:
However If I reload the collectionView after I select the cell the selection ordering begins to behave strangely. When I select the same top 3 cells in the same order from left to right, different cells become selected:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)! as! CustomCell
cell.backgroundColor = .red
collectionView.reloadData()
}
Apple's documentation is cryptic. https://developer.apple.com/documentation/uikit/uicollectionview/1618078-reloaddata
They say that "This causes the collection view to discard any currently visible items (including placeholders) and recreate items based on the current state of the data source object. " But this makes me think that upon calling reloadData() the collectionViewCells would go back to gray and not jump indexPaths.
Can anyone explain what is going on in reloadData() to make the cell selection at index path ordering so strange?
First You need to use dequeue cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:"CustomCell", for: indexPath) as! CustomCell
And in cell you can use
-(void)prepareForReuse {
// Set default implementation
}
new to swift. I have a nested CollectionView from one viewcontroller. The main viewcontroller has 7 collectionviewcell ("Level1Cell" in the code below). Each time I click a button or trigger an event, I want the collectionView to reload with the new data.
func eventHandler() {
// updates data
myCollectionView.reloadData()
}
Then, after it calls reload, it will call the reload again on each of the the nested CollectionViewCell.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Level1Cell", for: indexPath) as! Level1Cell
cell.appsCollectionView.reloadData()
return cell
}
The problem is, let say I want to, for the first cell, set a particular row some text.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(self.index == 0 && indexPath.row == 30){
rightCell.textLabel.text = "asdasd"
}
The fourth "Level1Cell" cell somehow has its label set also at the 30th row, but not the second and third. After stepping through the debugger, I realize that the cells, after reloading, the fourth cell "Level1Cell" is set to have the the same memory address as the first cell ( why does reload do this - shouldn't it allocate a new memory for each "Level1Cell"? - how can I get around this). Also, should I not use reload to update the data in the view and nested view of those from the view controller?
Thanks!
UIcollectionview will reuse cells. You must provide needed data for row in method
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
Or just clear previous data at cell.
I have put UITableView in UICollectionView, and it has 4 items, but when I scroll UICollectionView to the last item, it shows the content of the first UITableView ( So when I press option 3 button it scrolls to the last item of collectionView but the content is wrong ) . You can have a look at the below picture.
Below is the link to my project, please help me out with this issue.
Link to my project
You have to reload the UITableView in cellForItemAt as mentioned below.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TableCollectionCell", for: indexPath) as! TableCollectionCell
cell.tableView.tag = indexPath.item
cell.tableView.reloadData()
return cell
}