multiple cells selected on scrolling [reuse cells problem]
Maintain global variable in your controller
var mLastSelectedIndex = -1
Whenever cellForRowAtIndexPath method called check if current cell is selected or not .If this is selected One update its UI. I suggest you to change selected cell UI on cell class only. This way you can easily manage cell tapping and helps you writing clean code.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = attachProfilesCollectionView.dequeueReusableCell(withReuseIdentifier: "attachCells", for: indexPath) as? attachUsersCell
cell!.subscribedUserId = self.followedUsers[indexPath.row].userId
cell?.profileNameToAttah.text = self.followedUsers[indexPath.row].fullName
cell?.profileImageToAttch.loadImagesWithUrl(from: self.followedUsers[indexPath.row].ImagePath)
// here update selected index path
if mLastSelectedIndex == indexPath.row {
cell?.isSelected = true
}
else{
cell?.isSelected = false
}
return cell!
}
Update last selected index on cell tapped.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard mLastSelectedIndex != IndexPath.row else{return}
let indexpath = IndexPath(row:mLastSelectedIndex, section: 0)
mColllectionView.cellForItem(at: indexpath)?.isSelected = !mColllectionView.cellForItem(at: indexpath)!.isSelected
mLastSelectedIndex = IndexPath.row
}
In your attachUsersCell.swift declare isSelected property of cell . The default value of this property is false, which indicates that the cell is not selected.
override var isSelected: Bool{
didSet{
if isSelected {
setSelectedUI()
}
else{
setUnSelectedUI()
}
}
}
func setSelectedUI(){
borderColor = UIColor.systemOrange
borderWidth = 2
cornerRadius = 8
clipsToBounds = true
}
func setUnSelectedUI(){
// reset to default ui
}
Hope this helps!
Multiple Cells selected on scrolling in collection view
Because the cells are being reused that's why it's making a problem. Better use like this:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"AppliancesCell";
_appliancesViewCell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
collectionView.allowsMultipleSelection = YES;
if ([cell isSelected]) {
_appliancesViewCell.contentView.backgroundColor = [UIColor blackColor];
}else {
_appliancesViewCell.contentView.backgroundColor = [UIColor clearColor];
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
_appliancesViewCell = (CategoryListCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
_appliancesViewCell.contentView.backgroundColor = [UIColor blackColor];
}
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
_appliancesViewCell = (CategoryListCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
_appliancesViewCell.contentView.backgroundColor = [UIColor clearColor];
}
my table view reuse the selected cells when scroll -- in SWIFT
You currently store the selection state in the backgroundColor. That's not a good idea because for performance reasons cells will be reused by the tableView.
You should save the selected indexPaths in the data model. If you want to allow multiple selection you can store the selected indexPaths in a NSMutableSet.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.selectionStyle = .None
configure(cell, forRowAtIndexPath: indexPath)
return cell
}
var selectedIndexPaths = NSMutableSet()
func configure(cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
cell.textLabel!.text = "Row \(indexPath.row)"
if selectedIndexPaths.containsObject(indexPath) {
// selected
cell.backgroundColor = UIColor.redColor()
}
else {
// not selected
cell.backgroundColor = UIColor.whiteColor()
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if selectedIndexPaths.containsObject(indexPath) {
// deselect
selectedIndexPaths.removeObject(indexPath)
}
else {
// select
selectedIndexPaths.addObject(indexPath)
}
let cell = tableView.cellForRowAtIndexPath(indexPath)!
configure(cell, forRowAtIndexPath: indexPath)
}
If you only need single selection you should save the selected indexPath in an NSIndexPath? instance variable
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.selectionStyle = .None
configure(cell, forRowAtIndexPath: indexPath)
return cell
}
var selectedIndexPath: NSIndexPath?
func configure(cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
cell.textLabel!.text = "Row \(indexPath.row)"
if selectedIndexPath == indexPath {
// selected
cell.backgroundColor = UIColor.redColor()
}
else {
// not selected
cell.backgroundColor = UIColor.whiteColor()
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if selectedIndexPath == indexPath {
// selected same cell -> deselect all
selectedIndexPath = nil
}
else {
// select different cell
let oldSelectedIndexPath = selectedIndexPath
selectedIndexPath = indexPath
// refresh old cell to clear old selection indicators
var previousSelectedCell: UITableViewCell?
if let previousSelectedIndexPath = oldSelectedIndexPath {
if let previousSelectedCell = tableView.cellForRowAtIndexPath(previousSelectedIndexPath) {
configure(previousSelectedCell, forRowAtIndexPath: previousSelectedIndexPath)
}
}
}
let selectedCell = tableView.cellForRowAtIndexPath(indexPath)!
configure(selectedCell, forRowAtIndexPath: indexPath)
}
Collection view cells duplicate when scrolling
The problem is that you don't specify what text to appear on each of your CollectionViewCell's textView. As long as you don't specify the same in cellForItemAt indexPath
it is going to show the reused cell and its content, from dequeueReusableCell
as you said.
For the solution to your specific problem you can do as below in the viewcontroller:
`var textViewContentArray = [Int: String]()` //Create a dictionary to hold the texts globally
In textViewDidEndEditing:
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.textColor = .gray
textView.text = "Chapter Title"
} else {
guard let cell = textView.superview?.superview as? CustomWriterPageCell else {
return
}
guard let indexPath = self.collectionView.indexPath(for: cell) else { return }
textViewContentArray[indexPath.row] = textView.text
}
}
In textViewDidBeginEditing:
func textViewDidBeginEditing(_ textView: UITextView) {
textView.textColor = .black
}
And in cellForItemAt indexPath:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomWriterPageCell", for: indexPath) as! CustomWriterPageCell
cell.textView.delegate = self
let text = textViewContentArray[indexPath.row]
if !text.isEmpty {
cell.textView.textColor = .black
cell.textView.text = text
} else {
cell.textView.textColor = .gray
cell.textView.text = "Chapter Title"
}
return cell
}
Note: Here I am assuming you have set the Controller which holds the collectionView as delegate for the textViewInCell, if the cell is the delegate you can update the textViewContentArray using protocol
Hope this adds to your understanding.
Scrolling in UICollectionView selects wrongs cells - Swift
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.
Prevent selected cell from being reused
You can maintain a selectedIndex variable.
In your cellForRow you check whether this call is for selectedCell. If yes, then do the customisation that is required for selected cell.
Also you might want to handle heightForRow, there also check whether the call is for selected cell.
You can maintain an indexPath for selected cell. If there are multiple sections.
No need to prevent it from getting reused.
Hope that helps.
UICollectionView showing wrong cells after scrolling - dequeue issue?
I've had similare issues. This is most likely because the reused cells do not redraw themselves. In your custom cell's content class (your PDF view), trigger redrawing if the frame is updated:
-(void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self setNeedsDisplay]; // force drawRect:
}
This worked for me. In addition, if your cell size may change, set the autoresizing mask so that it fills space with
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
during initialization.
Related Topics
iOS Firebase Database Get Key of Value
Exc_Breakpoint (Sigtrap) on Production Version Only
Post Parameter to Sever Using Dictionary Swift
How to Create a "Hyperlink" with Swift
Uitableviewcell Custom Class - Reload Cell Height After Change in Subview Height Constraint
How to Add the Same Background Image to All Views in My iOS App Using Swift
Ios-Charts How to Put Uiimage Beside a Point
Xcode 11 Archive Gives Phasescriptexecution Failed
Records, Zone Doesn't Displayed in Dashboard and Delete Zone Issue Cloudkit
Gmsmapview Animatetocameraposition Zoom in - Zoom Out Animation
iOS Swift Flood Fill Algorithm
How to Remove Single Object in Array from Multiple Matching Object
Navigationlink Inside Lazyvgrid Cycles All Entries on Back, Swiftui
Get Light or Dark Variant of a Color Declared in Assets