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
Related
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;
}
I'm trying to fill a collectionview with data from an array which I've checked it has the data, but at runtime it's filling just the cell at index 0.
The collectionview is a list of friends in pages of 9 items showing photo and name. The number of items at section is working properly, I mean, if the array has 3 objects, the collectionview displays three cells but just the first one with the photo and name of the object, concretly the last one in the array, not the first one. And the other cells show the prototype cell.
I guess I'm dealing wrong with the indexpath of the collection view, but I have another one in my storyboard and works properly. This other one has only one cell per page, could be something related to this?
I paste my collectionview methods:
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.miListaAmigos count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"friendCell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
UILabel *nameLabel = (UILabel *)[self.view viewWithTag:102];
nameLabel.font = [UIFont fontWithName:#"Ubuntu" size:12.0];
nameLabel.text = [[self.miListaAmigos objectAtIndex:indexPath.row] valueForKey:#"usr_username"];
return cell;
}
you not directly reuse UILabel from self.view, UILabel *nameLabel = (UILabel *)[self.view viewWithTag:102];
try this below code for solve your problem:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"friendCell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
if(cell == nil)
{
//Create UILabel here
UILabel *nameLabel=[[UILabel alloc]initWithFrame:CGRectMake(5, 5, 310, 20)];
nameLabel.tag=100;
[cell addSubview:nameLabel];
nameLabel.font = [UIFont fontWithName:#"Ubuntu" size:12.0];
}
// Access label and reuse
UILabel *nameLabel = (UILabel *)[cell viewWithTag:100];
nameLabel.text = [[self.miListaAmigos objectAtIndex:indexPath.row] valueForKey:#"usr_username"];
return cell;
}
Check your collectionView alloc and required deleagte:
UICollectionViewDelegatećUICollectionViewDataSourceć UICollectionViewDelegateFlowLayout.
e.g.
UICollectionViewFlowLayout *collectionLayout = [[UICollectionViewFlowLayout alloc] init];
[collectionLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:collectionLayout];
[collectionView registerClass:[CNCollectionViewCell class] forCellWithReuseIdentifier:cellIndetify];
collectionView.delegate = self;
collectionView.dataSource = self;
[self.view addSubview:collectionView];
Your label is in self.view not in the cell... You really should make a subclass of UICollectionViewCell
File -> New -> File -> Cocoa Touch Class
Class: MYFriendCollectionViewCell
Subclass of: UICollectionViewCell
Also Create XIB: Tick
Language: Objective C
Look at MYFriendCollectionViewCell.xib and make your label inside here... connect the labels to an IBOutlet... don't use tags...
#property (weak, nonatomic) IBOutlet UILabel *nameLabel;
https://www.youtube.com/watch?v=GusRijNLUGg <- connecting IBOutlets
Add the line below in your ViewController
[self.collectionView registerNib:[UINib nibWithNibName:#"MYFriendCollectionViewCell" bundle:nil] forCellWithReuseIdentifier: CellIdentifier];
Change your cellForItem to:
static NSString *CellIdentifier = #"friendCell";
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath{
MYFriendCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: CellIdentifier forIndexPath: indexPath];
cell.nameLabel.font = nameLabel.font = [UIFont fontWithName:#"Ubuntu" size:12.0]; // This ideally would be in MYFriendCollectionViewCell.m
cell.nameLabel.text = [[self.miListaAmigos objectAtIndex:indexPath.row] valueForKey:#"usr_username"];
return cell;
}
Hi i'm trying to customize my collectionviewcell depending on its indexPath but also if I set
if (indexPath.row == 0)
{
[cell addSubView: view];
}
the view appear random in some cells.
This is the code I'm using
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 15;
}
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
NSInteger row = indexPath.row;
UIView *contentCell = [[UIView alloc] initWithFrame:cell.frame];
if (row == 0)
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(1.0f, 1.0f, 50.0f, 50.0f)];
label.text = #"Test";
[contentCell addSubview:label];
}
[cell addSubview:contentCell];
cell.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"container"]];
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%d", indexPath.row);
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(414, 228);
}
You have to read about reusable cells.
you can avoid the problem for now by doing this.
if (row == 0)
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(1.0f, 1.0f, 50.0f, 50.0f)];
label.text = #"Test";
label.tag = 200;
[contentCell addSubview:label];
}else{
UIView* lbl = [contentCell viewWithTag:200];
if(lbl)
[lbl removeFromSuperView];
}
but this will affect the scrolling and memory performance, you can put the label in the cell by default && show/hide it in the if/else blocks
You are adding view several times as a subview. Cells are reused due to "dequeueReusableCellWithReuseIdentifier", so after you scroll up and down, you get back existing view, which already has subview added.
You should read more about reusing cells.
One way to avoid that behavior is to create all views when you create a cell and just show / hide them.
Otherwise create cells with different identifier for different rows - in your case for row 0.
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()'