I wonder which's the easiest way to have two different UICollectionViewCells-identifiers in the same UICollectionView? I've got an UISegmentedController that I want to switch between to different styles of UICollectionViewCells.. Where to implement which code. I've got an PatternViewCell for the first Cell but how do i do with the other? Please advice!
You can have two collection view cell prototypes registered for a single cell class for a single collection view with a single data source.
First, in your storyboard, set Cell1 as a reuse identifier for the first cell prototype and Cell2 for the second one. Both of them should have PatternViewCell class.
Then, on changing value of your segmented control you reload your collection view:
- (IBAction)segmentedControlValueChanged:(id)sender {
[self.collectionView reloadData];
}
Bind this action to your segmented control for the Value Changed event.
Then in - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath method you can choose a reuse identifier depending on selected index.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = nil;
if (self.segmentedControl.selectedSegmentIndex == 0) {
identifier = #"Cell1";
} else {
identifier = #"Cell2";
}
PatternViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
//configure cell
return cell;
}
Related
I'm creating a custom collectionViewCell called MessageCell. This message cell has three components, a headerLabel, messageContainerView, and footerLabel. The problem is that depending on the type of message (video, transaction, delivery confirmation, photo, text, etc) I want to display a specific type of view with specific actions etc.
What's the best way to accomplish this? I've tried setting up my container view as a UIView in my cell subclass, and depending on the type of message, set it equal to a specific subview but that isn't working:
- (void)setMessage:(EMKMessage *)message {
//Set Message
_message = message;
//Check Message Type
switch (message.type) {
case MessageTypeText:
default: {
//Create Message Content View
TextContentView *textContentView = [[TextContentView alloc] initForAutoLayout];
textContentView.frame = CGRectMake(0, 0, 300, 200);
[textContentView setText:message.text];
self.messageContainerView = textContentView;
break;
}
}
}
Any help would be greatly appreciated.
You can create separately all the cells you need. In
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
you can renturn different cells depending on your needs. Just check the type of object you want to represent at the indexPath and return the corresponding cell. Those cell can have delegates if you need to interract with them or you can use block properties. Something like:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
VideoMessageCell *cell = [tableView.dequeueReusableCellWithIdentifier:#"VideoMessageCell"];
//set the cell properties
return cell;
} else if (indexPath.row == 1) {
AudioMessageCell *cell = [tableView.dequeueReusableCellWithIdentifier:#"AudioMessageCell"];
//set the cell properties
return cell;
}
}
Now, I don't know how you decide which type of cell do you need for a given index but you can replace indexPath.row to suit your needs. Also do not forget to set reusable identifiers accordingly.
I implemented a calendar view with UICollectionView, when scrolling the calendar view very fast, it's not smooth. So I'm thinking whether I can load static content of each cell firstly, and then refresh once specific content has been loaded. So how to delay loading specific contents of each UICollectionViewCell
Specifically, in below function, I'll construct each UICollectionViewCell and return it. Now I just want to construct static contents (such as the date), and delay loading specific contents (such as the background color, if I have an event this day, I'll change the background of this cell), so where should I load specific contents, and how to only refresh showing cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:UICollectionViewCellIdentifier
forIndexPath:indexPath];
NSDate *date = [self dateAtIndexPath:indexPath];
cell.dateLabel.text = [date description];
// This is the part I want to delay, since it's cost.
if (dataModel.hasEventAtDate(date)) {
cell.dateLabel.backgroundColor = [UIColor blue];
}
return cell;
}
You may need have an instance variable to track if cells need to update:
Boolean cellNeedsUpdate = NO
In cellForItemAtIndexPath, check if you need to fully update the cells:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if (cellNeedsUpdate) {
// fully update the cell
} else {
// do partial update
}
}
Track end scrolling of the collectionView, then reload the collectionView:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
cellNeesUpdate = !cellNeedsUpdate;
[collectionView reloadData];
}
I can't solve next problem.
I want to display 20 table cells, each contains a unique UICollectionView.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *package=[_packageList objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"package";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UICollectionView *cellImageCollection=(UICollectionView *)[cell viewWithTag:9];
cellImageCollection.restorationIdentifier=[NSString stringWithFormat:#"%li", (long)indexPath.row, nil];
cellTracking.text=[NSString stringWithFormat:#"Row #%li",(long)indexPath.row];
return cell;
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
int row=[collectionView.restorationIdentifier intValue];
return [[[_packages objectAtIndex:row] valueForKey:#"imageGallery"] count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
int row=[collectionView.restorationIdentifier intValue];
NSString *imgStrLink=[[[_packages objectAtIndex:row] valueForKey:#"imageGallery"] objectAtIndex:indexPath.row];
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ImageID" forIndexPath:indexPath];
UIImageView *imageView=(UIImageView *)[cell viewWithTag:2];
imageView.image=....;
return cell;
}
Function tableView:cellForRowAtIndexPath: is called 20 times, but collectionView:numberOfItemsInSection: and collectionView:cellForItemAtIndexPath: only 4 times.
As seen in the screenshots UICollectionView is repeated every fourth line.
What is my fault?
I too faced this problem, the reason I got this problem was because both datasource and delegates for the tableview and collectionView were to the same parent viewcontroller.
It started working for me when I changed the datasource and delegate of the collectionView to another View say ParentView, and I added the collectionView to this ParentView and then finally added ParentView as conentView of the cell.
My previous answer which points to two nice tutorials was deleted by someone saying that I should include the essential parts of the content here(because the link may become invalid in future)...but I cannot do that as those are codes written by the tutorial owners and also the whole codes are essential too :), so now I am giving the link to the source code...
HorizontalCollectionViews
AFTabledCollectionView
-anoop
since Xcode 7 and iOS9 you can use UIStackView - best solution for design if collectionview or tableview are containing each other.
I have implemented an UICollectionView image gallery. Each cell has some views and I would like to hide or show that views when I change the current cell, at least when the event starts. is there any method? or should I do something by delegate? I have paging enabled and custom cell and FlowLayout.
I have done everything almost like this tutorial
One way would be to keep the current selected cell index in a local variable in your viewController, and use that index to perform any actions when selecting another cell:
#property (nonatomic) NSIndexPath *selectedCellIndexPath;
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (![self.selectedCellIndexPath isEqual:indexPath]) {
UICollectionViewCell *lastSelectedCell = [collectionView cellForItemAtIndexPath:selectedIndexPath];
// Perform any change to lastSelectedCell before deselecting it
[collectionView deselectItemAtIndexPath:lastSelectedIndexPath animated:YES];
}
self.selectedCellIndexPath = indexPath;
UICollectionViewCell *selectedCell = [collectionView cellForItemAtIndexPath:indexPath];
// Change what you want in the newly selected cell;
}
I want to design a page like this image for Ipad:
I decide to implement it by UICollectionViewController, and I am going to use UICollectionViewController for the first time.
I want to know, UICollectionViewController let me have various layout for cells? and how can I do that?
Yes you can have different layouts for cells.
In your UICollectionView, you will need to register the various cell classes that you are going to use:
[self registerClass:[Class1 class] forCellWithReuseIdentifier:#"Class1"];
[self registerClass:[Class2 class] forCellWithReuseIdentifier:#"Class2"];
Then in your datasource delegate:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
//Whatever logic you will use to distinguish between the two classes
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Class1" forIndexPath:indexPath];
//OR
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Class2" forIndexPath:indexPath];