Uicollectionview chess style grid - ios

I have to implement a chess style grid view to show some radial progress bar.!
I made the grid using some inefficient algorithm to do this, since UiCollectionView don't use rows and columns, and it worked, but when the user scrolled the collection to the limit and the "row" of the collection disappear from the screen and the user release the screen and the UICollectionViewCells reappear they switched its colors.
I know the switching happens by the BOOLs, but i don't know how solve this.
This is my algorithm (i have 2 differents UICollectionViewCells, one for each color)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
static NSString *identifierPair = #"CellPair";
UICollectionViewCell *cell ;
UILabel *title;
//...Creating the circle progress bar....
if ((indexPath.item % 2) == 0) {
if (isPair) {
cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifierPair forIndexPath:indexPath];
isPair = NO;
title = (UILabel *)[cell viewWithTag:12];
}
else
{
cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
isPair = YES;
title = (UILabel *)[cell viewWithTag:11];
}
}
else {
if (isUneven) {
cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifierPair forIndexPath:indexPath];
isUneven = NO;
title = (UILabel *)[cell viewWithTag:12];
}
else
{
cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
isUneven = YES;
title = (UILabel *)[cell viewWithTag:11];
}
}
//...Setting the name to the cell....
return cell;
}

This seems more the case of using a single checkered background inside the UICollectionView, but since I'm not sure that it is doable you could do something like:
+ (BOOL)checkersCellAtIndexIsDark:(NSIndexPath *)indexPath {
NSInteger squareIndex = indexPath.item % 4;
return (squareIndex == 0 || squareIndex == 3);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.backgroundColor = ([[self class] checkersCellAtIndexIsDark:indexPath])? [UIColor orangeColor] : [UIColor yellowColor];
// Set other things
return cell;
}
I don't understand why you use different reuseIdentifiers and titleLabels for different backgrounds since I don't notice from the screens, but you can always edit this code

You didn't have to use 2 different cells to change the background.
All you need is to set the default color of the background and when the indexPath.item is even, just set the other color for the cell background.
But is important to set the default color first, otherwise you will have the same result.

Related

CollectionView Highlights incorrect Cell When Scrolling

I have a UICollectionView. When an user clicks a cell the colour of the cell changes to red. I have coded the above part and it works perfectly.
However, when I scroll below, other cells in the collection view has got highlighted with the colour red. I am sure that it hasn't been selected but only highlighted.
How can I solve this.
My code is as follows:
cellForItemAtIndexPath Method
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"cell";
ViewCell *vc = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
vc.vciv.image = [arrayOfImages objectAtIndex:indexPath.row];
return vc;
}
didSelectItemAtIndexPath Method
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if([items containsObject:allItem[indexPath.row]] ){
UICollectionViewCell *c =[collectionView cellForItemAtIndexPath:indexPath];
c.backgroundColor = [UIColor clearColor];
} else {
UICollectionViewCell *c =[collectionView cellForItemAtIndexPath:indexPath];
c.backgroundColor = [UIColor redColor];
}
As the collection view cells get reused, you need to make sure a dequeued cell is not highlighted in the cellForItemAtIndexPath: method:
UICollectionViewCell *vc = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
vc.backgroundColor = [UIColor clearColor];
This code will clear the cell's background always when dequeuing. If you need to preserve the highlighting, you need to store the indexPaths of the cells that you want to have highlighted, and check for the current cell being in that list.
EDIT
It seems that your items variable is well suited to do that.
So you would do:
UICollectionViewCell *vc = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
vc.backgroundColor = [items containsObject:allItem[indexPath.row]] ? [UIColor redColor] : [UIColor clearColor];

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

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

UICollectionViewCell Selection selects/highlights every 5 cells

I have a horizontal collectionview with code to highlight/color the cell selected. It highlights the cell that was selected, but then every 5 cells after also get highlighted. Any idea what is going on?
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
for(int x = 0; x < [cellArray count]; x++){
UICollectionViewCell *UnSelectedCell = [cellArray objectAtIndex:x];
UnSelectedCell.backgroundColor = [UIColor colorWithRed:0.2 green:0.5 blue:0.8 alpha:0.0];
}
UICollectionViewCell *SelectedCell = [cellArray objectAtIndex:indexPath.row];
SelectedCell.backgroundColor = [UIColor colorWithRed:0.2 green:0.5 blue:0.8 alpha:1.0];
cellSelected = indexPath.row;
NSLog(#"%i", cellSelected);
}
That happens because cells are reused when you scroll. You have to store the "highlighted" status for all rows in your model (for example in an array or NSMutableIndexSet), and in collectionView:cellForItemAtIndexPath: set the background color of the cell according to the status for that row.
In didSelectItemAtIndexPath it should be sufficient to set the color of the newly selected
and the previously selected cell.
Update: If only one cell can be selected at a time, you just have to remember the
index path of the selected cell.
Declare a property selectedIndexPath for the currently highlighted row:
#property (strong, nonatomic) NSIndexPath *selectedIndexPath;
In didSelectItemAtIndexPath, unhighlight the previous cell, and highlight the new cell:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (self.selectedIndexPath != nil) {
// deselect previously selected cell
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:self.selectedIndexPath];
if (cell != nil) {
// set default color for cell
}
}
// Select newly selected cell:
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
if (cell != nil) {
// set highlight color for cell
}
// Remember selection:
self.selectedIndexPath = indexPath;
}
In cellForItemAtIndexPath, use the correct background color:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Identifier" forIndexPath:indexPath];
if ([self.selectedIndexPath isEqual:indexPath) {
// set highlight color
} else {
// set default color
}
}
I think you use reusable cell for collection - there is the point.
You shell to set default background color before reuse cell.

Highlight collection cell when selected

I am trying to highlight a selected collection cell in UICollectionView with yellow border so user can see which one is currently selected. I tried this:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
FilterCell *filterCell = (FilterCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"FilterCell" forIndexPath:indexPath];
filterCell.window.backgroundColor = [UIColor yellowColor];
filterCell.backgroundColor = [UIColor yellowColor];
NSLog(#"hello");
}
There are 2 empty pixels around UIImageView inside UICollectionViewCell so it should work but it doesn't.
It is logging "hello" but the border stays black. See this screenshot:
You are getting the cell in the wrong way
FilterCell *filterCell = (FilterCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"FilterCell" forIndexPath:indexPath];
will dequeue a cell which is not used right now or allocate a new one with the specified identifier.
Use
FilterCell *filterCell = (FilterCell *)[collectionView cellForItemAtIndexPath:indexPath];
instead.
Anyway a cleaner solution would be to set the backgroundView and selectedBackgroundView properties of the cell, without touching the backgroundProperty color (that will stay clear as default). In this way you can avoid the delegate method and achieve the same behavior.
Do a reloadItemsAtIndexPaths: there instead, then in cellForItemAtIndexPath, check if [[collectionView indexPathsForSelectedItems] containsObject:indexPath] If true, change the cell's attributes there.
This may help you:
cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"YOUR_FILE_NAME.png"]];
-This code may help you to change background colour of selected cell
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cvCell" forIndexPath:indexPath];
if (cell.selected) {
cell.backgroundColor = [UIColor blueColor]; // highlight selection
}
else
{
cell.backgroundColor = [UIColor redColor]; // Default color
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
datasetCell.backgroundColor = [UIColor blueColor]; // highlight selection
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
datasetCell.backgroundColor = [UIColor redColor]; // Default color
}

Resources