Reusing cell causes unwanted behaviour when updating cell view - ios

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;
}

Related

UICollectionView handle selection with NSIndexPath

I'm using a collection view in my app with the selection of cells ..
To handle the selection I am using an NSIndexPath that I call in didSelectItemAtIndexPath and in didDeselectItemAtIndexPath.
The selection seems to work fine but when I select two cells nearby it seems that the didDeselectItemAtIndexPath is not called ... where am I doing wrong?
this is my code
#property (nonatomic, strong) NSIndexPath *selectedIndex;
#implementation YearSelector
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
YearCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:yearCellID forIndexPath:indexPath];
cell.yearLabel.text = [NSString stringWithFormat:#"%#", self.yearArray[indexPath.item]];
if ([indexPath isEqual:self.selectedIndex]) [cell highlightedYear:YES];
else [cell highlightedYear:NO];
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *newIndex = [NSIndexPath indexPathForItem:indexPath.item inSection:0];
[collectionView scrollToItemAtIndexPath:newIndex atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
YearCell *cell = (YearCell *)[collectionView cellForItemAtIndexPath:indexPath];
_selectedIndex = indexPath;
[cell highlightedYear:YES];
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
YearCell *cell = (YearCell *)[collectionView cellForItemAtIndexPath:indexPath];
[cell highlightedYear:NO];
_selectedIndex = nil;
}
This is the code I use for highlighted cell ( Custom Year Cell)
-(void)highlightedYear:(BOOL)highlighted {
if (highlighted) {
_baseView.backgroundColor = [UIColor colorWithHexString:#"#FF7751" setAlpha:1];
_baseView.layer.borderColor = UIColor.clearColor.CGColor;
_yearLabel.textColor = UIColor.groupTableViewBackgroundColor;
}
else {
_baseView.backgroundColor = [UIColor colorWithHexString:#"#272D3D" setAlpha:1];
_baseView.layer.borderColor = [UIColor colorWithHexString:#"#485674" setAlpha:1].CGColor;
_yearLabel.textColor = UIColor.groupTableViewBackgroundColor;
}
}

UICollectionViewCell background color change works in cellForItemAtIndexPath but not didSelectItemAtIndexPath

I can change my collection view cell background color in cellforitematindexpath but not in didselectitematindexpath using the code below (i only change the color in one place however). How does this happen? I know that didselectitematindexpath is being called.
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CollectionViewCell *cell = [cv dequeueReusableCellWithReuseIdentifier:#"CollectionView" forIndexPath:indexPath];
cell.layer.borderWidth=1.0f;
cell.layer.borderColor=[UIColor grayColor].CGColor;
cell.label.text = #"test"
cell.contentView.backgroundColor = [UIColor redColor];
return cell;
}
-(void)collectionView:(UICollectionView *)cv didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"selected cell");
CollectionViewCell *cell = [self collectionView:cv cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor redColor];
}
Several things wrong here.
You're using the wrong method to get the selected cell. Never call the delegate method directly, instead ask the collection view for the cell directly like this:
CollectionViewCell *cell = [cv cellForItemAtIndexPath:indexPath];
You're modifying the cell in a place where those modifications will not persist. When you scroll and that cell gets reused, the color will get wiped out. Instead you should call reloadItemsAtIndexPaths: when the cell gets selected, and have some code in collectionView:cellForRowAtIndexPath that checks the selected property of the cell and sets the color you want based on that. That way, the layout will remain consistent when you scroll and cells are reused.
use this..
self.collectionView.allowsMultipleSelection = YES;
then..
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath**
{
static NSString *identifier = #"Cell";
RecipeViewCell *cell = (RecipeViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.image = [UIImage imageNamed:[recipeImages[indexPath.section] objectAtIndex:indexPath.row]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"photo-frame-2.png"]];
cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"photo-frame.png"]];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (shareEnabled) {
NSString *selectedRecipe = [recipeImages[indexPath.section] objectAtIndex:indexPath.row];
[selectedRecipes addObject:selectedRecipe];
}
}
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (shareEnabled) {
NSString *deSelectedRecipe = [recipeImages[indexPath.section] objectAtIndex:indexPath.row];
[selectedRecipes removeObject:deSelectedRecipe];
}
}

How do I add a counter to a cell in UICollectionView cells?

I have the following code:
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
return cell;
}
How do I add a counter to dispaly in my cell that shows the number of the cell in the order it was created? Like cell 1 would say 1, 2 is 2, and so on.
Create a subclass of UICollectionViewCell. Add the counter (maybe just a label?) in the init method of the cell. Register you class for a cell identifier of your wish
[self.collectionView registerClass:[MyCollectionViewCell class]
forCellWithReuseIdentifier:#"myCellIdentifier"];
and dequeue the cell with the identifier. Then set the label value.
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"myCellIdentifier" forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
cell.counterLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
return cell;
}

Image of cell does not change in didDeselectItemAtIndexPath

I try to change status of image in the cell of the UICollectionView object...
this is a part of my code:
-(UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
cell *aCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"myCell" forIndexPath:indexPath];
[aCell.myImage setImage:[UIImage imageWithContentsOfFile:self.imageArray[indexPath.item]]];
if (aCell.selected) {
aCell.myImage.layer.borderWidth = 1.0;
aCell.myImage.layer.borderColor = [UIColor blackColor].CGColor;
aCell.mySelect.hidden = NO;
} else {
aCell.myImage.layer.borderWidth = 0.0;
aCell.myImage.layer.borderColor = nil;
aCell.mySelect.hidden = YES;
}
return aCell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Select");
cell *selectedCell= [collectionView dequeueReusableCellWithReuseIdentifier:#"myCell" forIndexPath:indexPath];
if (selectedCell.selected) {
[selectedCell.mySelect setImage:[UIImage imageNamed:#"select.png"]];
selectedCell.myImage.layer.borderWidth = 1.0;
selectedCell.myImage.layer.borderColor = [UIColor blackColor].CGColor;
selectedCell.mySelect.hidden = NO;
} else {
[selectedCell.mySelect setImage:nil];
selectedCell.myImage.layer.borderWidth = 0.0;
selectedCell.myImage.layer.borderColor = nil;
selectedCell.mySelect.hidden = YES; }
}
when i tap any cell, the value select changes, but view object does not refresh.
you need to refresh your row selected with this methos from your didSelectItemAtindexPath method
- (void)reloadItemsAtIndexPaths:(NSArray *)indexPaths
I think you should override selected/highlighted property in your custom UICollectionViewCell subclass for this task instead of using reload.
cell *selectedCell= [collectionView dequeueReusableCellWithReuseIdentifier:#"myCell" forIndexPath:indexPath];
This code will create a NEW cell! Your viewController is not contain this cell!
You should use correct method for getting selected cell:
[yourContentView cellForItemAtIndexPath:indexPath];
Why you are dequeue Cell, when cell is selected .
write following code
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath
{
NSLog(#"Select");
cell *selectedCell= (cell *)[collectionView cellForItemAtIndexPath:indexPath];
[selectedCell.mySelect setImage:(selectedCell.selected) ? [UIImage imageNamed:#"select.png"]: nil];
[collectionView reloadItemsAtIndexPaths:indexPath];
}

UICollectionView cell is not getting added as a subview of UICollectionView

I am new to UICollectionView.
I have followed this tutorial to learn how to use a UICollectionView, but the problem is that in the .xib (not using storyboard) I am not able to add UICollectionViewCell as a subview of UICollectionView.
In the tutorial the cell is automatically created under UICollectionView in the .xib.
Any help would be appreciated.
That tutorial is for working in stroy board in xib you ve to create custom cell first create view controller add UicollectionView to view Controller
then create custom class for collection cell
then craete empty xib resource and add collection view cell
and set class name and identifier for that control
then create delegates method to add custom cell to ur collectionViewController
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"customCell";
customCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
return cell;
}
You can start your controller and create a custom collection view cell for setting your view element and then you can use it into your collection view controller into xib, here is a good tutorials to do this http://adoptioncurve.net/archives/2012/09/a-simple-uicollectionview-tutorial/
Use this code for creation of collectionview and adding the subview.
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return [imageArray count];
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
NSMutableArray *sectionArray = [imageArray objectAtIndex:section];
return [sectionArray count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// Setup cell identifier
static NSString *cellIdentifier = #"cvCell";
/* Uncomment this block to use nib-based cells */
// UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
// UILabel *titleLabel = (UILabel *)[cell viewWithTag:100];
// [titleLabel setText:cellData];
/* end of nib-based cell block */
/* Uncomment this block to use subclass-based cells */
CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
NSMutableArray *data = [imageArray objectAtIndex:indexPath.section];
NSString *cellData = [data objectAtIndex:indexPath.row];
[cell.titleLabel setText:cellData];
cell.imageView.image = [UIImage imageNamed:[imageArray[indexPath.section] objectAtIndex:indexPath.row]];
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
header *sectionHeader;
if (kind == UICollectionElementKindSectionHeader)
{
sectionHeader = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"Hello" forIndexPath:indexPath];
}
UICollectionReusableView *test=[collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"Hello" forIndexPath:indexPath];
return test;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
if (section == 3) {
return CGSizeMake(0, 100);
}
return CGSizeZero;
}
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(80, 80);
}

Resources