UiCollectionViewCell border moves cells when i scroll - ios

So pretty much, when I try to scroll my UICollectionView while I a cell is selected, shown by a thin orange border, when I scroll back a different cell has the border. I read that it had something to do with cell's being reused. Anyways I found some code online, but just been having a hard time adapting it to multiple selection.
Found a solution to this problem all you have to do is make an array of selected cells and add or remove borders in
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
method
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
//each cell is refreshed when page is scrolled
//Matches every cell to see if it is selected or not and adds or removes borders accordinglly
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:indexPath.item];
if ( [selectedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]] )
{
[cell.layer setBorderColor:[UIColor orangeColor].CGColor];
cell.layer.borderWidth = 5.0f;
}
else
{
[cell.layer setBorderColor:[UIColor clearColor].CGColor];
cell.layer.borderWidth = 0.0f;
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
//Adds cells indexPath to selectedCellsArray and adds border around the cell right away
NSLog(#"selected");
UICollectionViewCell*selectedCell = [collectionView cellForItemAtIndexPath:indexPath];
if (![selectedCellsArray containsObject:[NSString stringWithFormat:#"%d",indexPath.item]] ) {
[selectedCellsArray addObject:[NSString stringWithFormat:#"%d",indexPath.item]];
[selectedCell.layer setBorderColor:[UIColor orangeColor].CGColor];
selectedCell.layer.borderWidth = 5.0f;
NSLog(#"add");
}
NSLog(#"keep track of array:%#", selectedCellsArray);
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
//Removes cells indexPath from selectedCellsArray and removes border form cell right away
NSLog(#"deselected");
UICollectionViewCell*deselectedCell = [collectionView cellForItemAtIndexPath:indexPath];
if ( [selectedCellsArray containsObject:[NSString stringWithFormat:#"%d",indexPath.item]] )
{
[selectedCellsArray removeObject:[NSString stringWithFormat:#"%d",indexPath.item]];
[deselectedCell.layer setBorderColor:[UIColor clearColor].CGColor];
deselectedCell.layer.borderWidth = 0.0f;
NSLog(#"remove");
}
}

Related

How to Select single cell in CollectionView and deselecting all other cell

**
I have horizontal CollectionView in which selected cell have orange
gradient color and all other deselected cells gray color i m
using only didselect delegate method but i am getting problem of
multiple cells selected and i have problem with same concept in table
view while scrolling and i have searched a lot but i have not get
proper answer of cell reusability
**
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
DateTimeCell * cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"DateTimeCellID" forIndexPath:indexPath];
if (self.selectedIndexPath != nil && indexPath == self.selectedIndexPath)
{
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = cell.mainView.bounds;
gradient.startPoint = CGPointZero;
gradient.endPoint = CGPointMake(1, 1);
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:238.0/255.0 green:42.0/255.0 blue:123/255.0 alpha:1.0] CGColor],(id)[[UIColor colorWithRed:241.0/255.0 green:90.0/255.0 blue:41.0/255.0 alpha:1.0] CGColor], nil];
[gradient setMasksToBounds:NO];
cell.mainView.backgroundColor = [UIColor clearColor];
[cell.mainView.layer insertSublayer:gradient atIndex:0];
[indexPaths addObject:self.selectedIndexPath];
}
else
{
[cell.mainView setBackgroundColor:[self colorWithHexString:#"383F4A"]];
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
indexPaths = [NSMutableArray arrayWithObjects:indexPath, nil];
if (self.selectedIndexPath)
{
// if we had a previously selected cell
if ([indexPath compare:self.selectedIndexPath] == NSOrderedSame)
{
// if it's the same as the one we just tapped on, then we're unselecting it
NSLog(#"Selected");
}
else
{
// if it's different, then add that old one to our list of cells to reload, and
// save the currently selected indexPath
[indexPaths addObject:self.selectedIndexPath];
self.selectedIndexPath = indexPath;
}
}
else
{
// else, we didn't have previously selected cell, so we only need to save this indexPath for future reference
self.selectedIndexPath = indexPath;
}
dispatch_async(dispatch_get_main_queue(), ^{
[collectionView reloadItemsAtIndexPaths:indexPaths];
});
}
take a global selectedIndexPath globaly like below
NSIndexPath *selectedIndexPath = [[NSIndexPath alloc] indexPathForRow:0 inSection:0];
wrilte below code in delegate methods
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
DateTimeCell * cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"DateTimeCellID" forIndexPath:indexPath];
if self.selectedIndexPath == indexPath
{
// do what you want to do with your selected cell
}
else
{
// do what you want to do with your deselected cell
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedIndexPath = indexPath
[self.collectionView reloadData];
}

Update not visible cells in UICollectionView

I need an expandable UICollectionView in my app - so I came across this project (https://github.com/apploft/APLExpandableCollectionView). It's a subclass of UICollectionView that implements the expand and collapse behaviour.
I have extended the demo app to display a + or a - button in the expandable cells.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
APLCollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"APLCollectionViewCell" forIndexPath:indexPath];
if (indexPath.item == 0) {
cell.label.text = [NSString stringWithFormat:#"Section %li", (long)indexPath.section + 1];
cell.backgroundColor = [UIColor colorWithRed:58./255. green:165./255. blue:192./255. alpha:1.];
cell.indentView.hidden = YES;
cell.label_OnOff.text = #"+";
} else {
cell.label.text = [NSString stringWithFormat:#"Item %li", (long)indexPath.row];
cell.backgroundColor = [UIColor colorWithRed:58./255. green:165./255. blue:192./255. alpha:.5];
cell.indentView.hidden = NO;
[cell.label_OnOff setHidden:YES];
}
return cell; 
}
To switch between + and - I implemented the delegate methods:
- (void)collectionView:(UICollectionView *)collectionView didCollapseItemAtIndexPath:(NSIndexPath *)indexPath
{
APLCollectionViewCell *cell = (APLCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
cell.label_OnOff.text = #"+";
}
- (void)collectionView:(UICollectionView *)collectionView didExpandItemAtIndexPath:(NSIndexPath *)indexPath
{
APLCollectionViewCell *cell = (APLCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
cell.label_OnOff.text = #"-";
}
As you can see in the screenshot, the visible cells are updated correctly. Once I scroll down to the former invisible cells, the + button disappears.
This problem doesn't occur when there are only a few items in the UICollectionView, so that there is no need to scroll to further items.
Am I doing something wrong with IndexPath for invisble cells, or do you have any other hints for me?
Thank you!
Add the below line
cell.indentView.hidden = NO;
Just before your if else condition in cellForItemAtIndexPath. it may help you.
Thx Bhanu,
your answer pointed me to the right direction. The cells in the collectionview are REUSED, so I had to set cell.label_OnOff.hidden = NO; and cell.label_OnOff.hidden = YES; when I check for the IndexPath.

UICollectionViewCell does not take maximum width

I'm trying to make cells take as much width as possible, but I end up like this:
I have tried to remove margins, line spacing etc. in xcode:
But the horizontal margin is still huge, I want the same vertical margin applied.
Any ideas?
P.S attached example code:
- (void)viewDidLoad {
[super viewDidLoad];
self.collectionView.delegate = self;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 9;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
CollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
return cell;
}
You set the Collection cell to be 100x100, and to be 3 at row.
So the UICollectionView is minimum 300/300. If you make the view to be 320(normal iPhone width), then the Collection View set padding between the cells automatically.
EDIT:
Try:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
CollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
//3 because you wanted 3 cells. 18 is the min padding between the cell.
cell.frame.size.width = collectionView.frame.size.width/3-18;
return cell;
}

Reusing cell causes unwanted behaviour when updating cell view

I want ot set a border to a selected cell, i save a cell property that represents the selected one and manipulate it:
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
NSArray *eyeArray = [self eyesArrayConfigure][indexPath.row];
if (indexPath.row==5) {
int r = arc4random() % 6;
eyeArray = [self eyesArrayConfigure][r];
}
[borderedCell.contentView.layer setBorderWidth:0.0f] ;
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
borderedCell = cell;
[borderedCell.contentView.layer setBorderColor:self.view.tintColor.CGColor];
[borderedCell.contentView.layer setBorderWidth:3.0f];
}
and the cellForView: (Im usinng 2 types of cell identifiers because one cell contains a label - "Random cell":
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row ==5) {
UICollectionViewCell *randomCell =[collectionView
dequeueReusableCellWithReuseIdentifier:#"randomCell"
forIndexPath:indexPath];
randomCell.backgroundColor = [UIColor purpleColor];
borderedCell = randomCell;
[borderedCell.contentView.layer setBorderColor:self.view.tintColor.CGColor];
[borderedCell.contentView.layer setBorderWidth:3.0f];
return randomCell;
}
UICollectionViewCell *myCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
NSArray *eyeArray = [self eyesArrayConfigure][indexPath.row];
myCell.backgroundView = [[UIImageView alloc] initWithImage:eyeArray[1]];
return myCell;
}
What i get is if a click one cell it will be fine till i scroll and then i get weird behaviour when couple of cells might be with the border.
Thanks for the help.
The solution is to use a view model. You are already doing this for your cells' background views. Apply the same concept for the border.
#interface MyCollectionView ()
#property (nonatomic) NSInteger selectedRow;
#end
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
//update self.selectedRow and either reload entire collection view or just the currently selected and previously selected.
self.selectedRow = indexPath.row;
[collectionView reloadData];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *myCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
CGFloat borderWidth = (indexPath.row == self.selectedRow) ? 3.0 : 0.0;
[myCell.contentView.layer setBorderWidth:borderWidth];
return myCell;
}

How to wrap the UICollectionView

I have used a horizontal collection view for scrolling the UILabel. In my array i have 30 item. When i scroll to the 30th item it should again show the first item, its like a circular scroll. Following is my code and image which i want to achieve.
- (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.waitListArray.count;
}
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
WaitListWarningTimeCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCollectionViewIdentifier forIndexPath:indexPath];
cell.lblWaitingTime.text = [NSString stringWithFormat:#"%#m", self.waitListArray[indexPath.row]];
if ([self.waitListArray[indexPath.row] intValue]==0) {
cell.lblWaitingTime.text = #"Off";
}
if (indexPath.row == self.selectedIndex)
{
cell.lblWaitingTime.textColor = [UIColor blackColor];
}
else
{
cell.lblWaitingTime.textColor = [UIColor lightGrayColor];
}
return cell;
}
you can refer iCarousel it has some great examples of the functionality you want. Here is the link
iCarousel

Resources