I'm adding a button to a cell of a collection view as below
- (void)activateDeletionMode:(UILongPressGestureRecognizer *)gr
{
if (gr.state == UIGestureRecognizerStateBegan)
{
NSLog(#"deletion mode");
if(self.isDeleteActive == NO){
self.isDeleteActive = YES;
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[gr locationInView:self.collectionView]];
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
self.deletedIndexpath = indexPath.row;
self.deleteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.deleteButton addTarget:self
action:#selector(deleteImage:)
forControlEvents:UIControlEventTouchUpInside];
[self.deleteButton setBackgroundImage: [UIImage imageNamed:#"delete.png"] forState:UIControlStateNormal];
self.deleteButton.frame = CGRectMake(10, 0, 10, 10);
[cell addSubview:self.deleteButton];
}
}
}
The problem is, when the cell is reused when the collection view is scrolled, I see the button displayed in this cell too. How do I avoid this happening? Code for collection view below:
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
Cell *cell = [cv dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
cell.image.image = [self.imageArray objectAtIndex:indexPath.row];
return cell;
}
In the past I've done things like this, when adding the view add a tag:
self.deleteButton.frame = CGRectMake(10, 0, 10, 10);
//Mark the view with a tag so we can grab it later
self.deleteButton.tag = DELETE_BUTTON_TAG;
[cell addSubview:self.deleteButton];
Then remove it from any new recycled cells:
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
Cell *cell = [cv dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
//Remove the delete view if it exists
[[cell viewWithTag:DELETE_BUTTON_TAG] removeFromSuperview];
cell.image.image = [self.imageArray objectAtIndex:indexPath.row];
return cell;
}
Related
I want to display two collection view using segment controller, on change of segment second collection view will display.
my code is :
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"morningcell" forIndexPath:indexPath];
UICollectionViewCell *cell1 = [collectionView dequeueReusableCellWithReuseIdentifier:#"eveningcell" forIndexPath:indexPath];
if (_segment.selectedSegmentIndex == 0) {
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, cell.frame.size.height,cell.frame.size.width)];
lbl.text = [numbers objectAtIndex:indexPath.row];
[cell addSubview:lbl];
[lbl setTextAlignment:UITextAlignmentCenter];
return cell;
}
else{
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, cell1.frame.size.height,cell1.frame.size.width)];
lbl.text = [numbers objectAtIndex:indexPath.row];
[cell1 addSubview:lbl];
[lbl setTextAlignment:UITextAlignmentCenter];
return cell1;
}}
Do not create two collectionView for the task that you want because you can achieve it using a single collectionView.
#interface YourVC(), UICollectionViewDelegate, UICollectionViewDataSource {
NSArray *arrayOfModelsForFirstCollectionView;
NSArray *arrayOfModelsForSecondCollectionView;
}
#end
#implementation YourVC
-(void)viewDidLoad{
[super viewDidLoad];
//Fetch Data For both Segments Using Your Web API Call or Local Database API Call
}
-(IBAction)didChangeSegmentIndex:(id)sender{
//When segment is changed you need to tell your collectionView to update the data.
[self.collectionView reloadData];
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfRowsInSection:(NSInteger)section{
//When reloadData is call this method will check that which index is selected.
//And according to selection it will create number of cells.
if (self.segmentControl.selectedIndex == 0){
return arrayOfModelsForFirstCollectionView.count;
}else{
return arrayOfModelsForSecondCollectionView.count;
}
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
//While creating a cell it will check which segment is selected so it will initialize and create the cell with respect to selection of segments.
//Hence you have created two different cells in a single collectionView toggling with a segmentControl.
if (_segment.selectedSegmentIndex == 0) {
return [self makeCellForFirstSegmentAtIndexPath: indexPath];
}
else{
return [self makeCellForSecondSegmentAtIndexPath: indexPath];
}
}
-(UITableViewCell *)makeCellForFirstSegmentAtIndexPath:(NSIndexPath *)indexPath{
//To show data from array you need to use arrayOfModelsForFirstCollectionView because this array is associated with First Segment Index
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"morningcell" forIndexPath:indexPath];
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, cell.frame.size.height,cell.frame.size.width)];
lbl.text = [arrayOfModelsForFirstCollectionView objectAtIndex:indexPath.row];
[cell addSubview:lbl];
[lbl setTextAlignment:UITextAlignmentCenter];
return cell;
}
-(UITableViewCell *)makeCellForSecondSegmentAtIndexPath:(NSIndexPath *)indexPath{
//To show data from array you need to use arrayOfModelsForSecondCollectionView because this array is associated with Second Segment Index
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"eveningcell" forIndexPath:indexPath];
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, cell.frame.size.height,cell.frame.size.width)];
lbl.text = [arrayOfModelsForSecondCollectionView objectAtIndex:indexPath.row];
[cell addSubview:lbl];
[lbl setTextAlignment:UITextAlignmentCenter];
return cell;
}
#end
I have a collection view and i want to add an image , with inner effect when one item is selected .
I made this but when i do scroll another item has the same effect and i don't want. How can i change this ?
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CollectionViewCell *cellO = [self.collection cellForItemAtIndexPath:celulaSelectata];
if ([selectedIndexPath isEqual:indexPath]) {
UIImage *inerImager =(UIView *)[cell viewWithTag:100];
cellO.inner.hidden=YES;
return CGSizeMake(100, 100);
}
else {
cellO.inner.hidden=NO;
return CGSizeMake(100, 100);
}
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
CollectionViewCell *cellOne = [collectionView cellForItemAtIndexPath:indexPath];
cellOne.inner.hidden=YES;
recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.frame=CGRectMake(recipeImageView.frame.origin.x, recipeImageView.frame.origin.y, 100, 100);
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if ([selectedIndexPath isEqual:indexPath]) {
selectedIndexPath = nil;
[self.player stop];
CollectionViewCell *cellOne = [collectionView cellForItemAtIndexPath:indexPath];
cellOne.inner.hidden=YES;
recipeImageView.frame=CGRectMake(recipeImageView.frame.origin.x, recipeImageView.frame.origin.y, 100, 100);
recipeImageView.layer.borderColor = [[UIColor blackColor] CGColor];
}
else {
celulaSelectata=indexPath;
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
CollectionViewCell *cellOne = [collectionView cellForItemAtIndexPath:indexPath];
recipeImageView.frame=CGRectMake(recipeImageView.frame.origin.x, recipeImageView.frame.origin.y, 100, 100);
cellOne.inner.hidden=YES;
}
That is happening because cells are reused. In your CollectionViewCell class you have to implement the method:
-(void)prepareForReuse {
[super prepareForReuse];
//Clear the effect here.
}
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];
}
I have table view in side bar which is similar to facebook app. In my sidebar tableview i have imageview in each row. I want the imageview will be changed when i clicked the cell and it will be retain while for selecting another cell. Here is my code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];
}
[[cell.contentView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
UIView * contentView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 60)];
UIImageView * cellImg = [[UIImageView alloc]initWithFrame:CGRectMake(5,8,259, 60)];
[cellImg setImage:[UIImage imageNamed:[menuArr objectAtIndex:indexPath.row]]];
[contentView addSubview:cellImg];
[contentView setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:contentView];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
delegate.sideBarSelectedIndex = indexPath.row;
NSLog(#"delegate.sideBarSelectedIndex: %d",delegate.sideBarSelectedIndex);
[UIView commitAnimations];
if (self.sidebarDelegate) {
NSObject *object = [NSString stringWithFormat:#"ViewController%d", indexPath.row];
[self.sidebarDelegate sidebarViewController:self didSelectObject:object atIndexPath:indexPath];
[delegate.firstLensePageObj timerFunction:indexPath.row];
}
}
Try this in your didSelectRowAtIndexPath delegate method :-
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.imageView.image = [UIImage imageNamed:#"yourImage"];
Try this in cellForRowAtIndexPath.
UIImageView *selectedImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Your Image"]];
cell.selectedBackgroundView = selectedImageView;
Need to capture the selected indexpath in didSelectRowAtIndexPath: method and need to reload the tableview in that method. In cellForRowAtIndexPath need to check the selected index with current index.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];
}
[[cell.contentView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
UIView * contentView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 60)];
UIImageView * cellImg = [[UIImageView alloc]initWithFrame:CGRectMake(5,8,259, 60)];
if (delegate.sideBarSelectedIndex == indexpath.row){
//Selected cell
[cellImg setImage:[UIImage imageNamed:[selectedMenuArr objectAtIndex:indexPath.row]]];
}else {
//Unselected cell
[cellImg setImage:[UIImage imageNamed:[menuArr objectAtIndex:indexPath.row]]];
}
[contentView addSubview:cellImg];
[contentView setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:contentView];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
delegate.sideBarSelectedIndex = indexPath.row;
NSLog(#"delegate.sideBarSelectedIndex: %d",delegate.sideBarSelectedIndex);
[UIView commitAnimations];
if (self.sidebarDelegate) {
NSObject *object = [NSString stringWithFormat:#"ViewController%d", indexPath.row];
[self.sidebarDelegate sidebarViewController:self didSelectObject:object atIndexPath:indexPath];
[delegate.firstLensePageObj timerFunction:indexPath.row];
}
}
I have a problem with data reloading using UICollectionView. I have this array on the viewDidLoad to fill the UICollectionView.
array = [[NSMutableArray alloc] init];
[array addObject:#"1"];
[array addObject:#"2"];
[array addObject:#"3"];
[array addObject:#"4"];
[array addObject:#"5"];
[array addObject:#"6"];
and the method:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"Cell";
//cell = [[UICollectionViewCell alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
myCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, 100, 20)];
[titleLabel setText:[array objectAtIndex:indexPath.row]];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.backgroundColor = [UIColor clearColor];
[cell addSubview:titleLabel];
return cell;
}
I tap the UIButton and data is reloaded:
[myCollectionView reloadData];
Here how the data looks like before and after the reload:
You add a new label each time you tap the reload button. You should add the label once and change the label text according.
Here a simple example.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MyCell *cell = (MyCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"Cell"
forIndexPath:indexPath];
[cell setMyTextLabel:indexPath.row];
return cell;
}
where MyCell will contains a UILabel and a property to modify its text.
I really suggest to take a look at Fun with UICollectionView code by #Ben Scheirman.
Hope that helps.
P.S. Rename myCell to MyCell. A class should start with an uppercase letter.
You are adding your label when you tap reload button. In that case you are adding label again and again...
So there are three solutions:
Make your cell reusable
Remove your cell from superview in reload method.
You can check if label's text length is not equal to zero. In that case no need to add that label and change text.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
dispatch_async(dispatch_get_main_queue(), ^{
// ********* Changed *******
for (UIView *v in [cell.contentView subviews])
[v removeFromSuperview];
// ********** Changed **********
if ([self.collectionviewFlow.indexPathsForVisibleItems containsObject:indexPath]) {
NSString *img_name=[NSString stringWithFormat:#"%#_thumb%d.png",self.VaritiesName,(int)indexPath.row+1];
imageVw=[[UIImageView alloc]initWithImage:[UIImage imageNamed: img_name]];
imageVw.frame=CGRectMake(10,10,100,100);
[cell.contentView addSubview:imageVw];
}
});
cell.backgroundColor=[UIColor clearColor];
return cell;
}
It is quit late, but here is my solution.
if you used custom collectionviewcell
try to use 'func prepareForReuse()'