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);
}
Related
I have my data source methods
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 10;
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
LPDiaryCollectionViewCell *cell = (LPDiaryCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.testLabel.text = #"test";
return cell;
}
The cell is registered
[self.collectionView registerClass:[LPDiaryCollectionViewCell class] forCellWithReuseIdentifier:#"cell"];
Datasource, delegate and outlet are connected
But when I run, datasource methods don't get called and view is plain white with no UICollectionView showing.
EDIT: added the uicollectionview programattically instead. It displays but still no cell.
You have to set cell identifier for collection view cell in storybord(Ex. I have declared identifier = "ReuseCell") and used same storyboard identifer in cellForItemAtIndexPath method.
static NSString *identifier = #"ReuseCell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
static NSString *identifier = #"Yourcellname";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
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;
}
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;
}
I want to have two UICollectionView in same page. Two UICollectionView that would show different data as required. How can I do this?
Thanks in advance.
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifierHall2 = #"hall2";
/* Uncomment this block to use subclass-based cells */
timeCell *cell = (timeCell *)[myCollectionViewHall2 dequeueReusableCellWithReuseIdentifier:cellIdentifierHall2 forIndexPath:indexPath];
[cell.timeButton setTitle:[[allSimilarMutableArray valueForKey:#"showTime"] objectAtIndex:indexPath.item] forState:UIControlStateNormal];
return cell;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifierHall3 = #"hall3";
/* Uncomment this block to use subclass-based cells */
timeCell *cell = (timeCell *)[myCollectionViewHall3 dequeueReusableCellWithReuseIdentifier:cellIdentifierHall3 forIndexPath:indexPath];
[cell.timeButton setTitle:[[allSimilarMutableArray valueForKey:#"showTime"] objectAtIndex:indexPath.item] forState:UIControlStateNormal];
return cell;
}
You can do the same by differentiating in 'cellForItemAtIndexPath'
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if (collectionView == self.collectiveview1) {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CollectionCell" forIndexPath:indexPath];
UILabel *titleLabel = (UILabel *)[cell viewWithTag:100];
[titleLabel setText:celldata];
UIImageView *imageView = (UIImageView *)[cell viewWithTag:200];
[imageView setImage:[UIImage imageNamed:connimage]];
return cell;
} else {
static NSString *cellIdentifier = #"FollowCell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
UILabel *titleLabel = (UILabel *)[cell viewWithTag:100];
[titleLabel setText:celldata];
UIImageView *imageView = (UIImageView *)[cell viewWithTag:200];
[imageView setImage:[UIImage imageNamed:cellImage]];
return cell;
}
}
Hope it helps.
Because both UICollectionView's respond to the same protocol: UICollectionViewDataSource, you must differentiate between them in the method:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
You can do this multiple ways, depending on how your UICollectionView's are created.
1. If you created them in Storyboard or in Interface Builder, link them to your class using IBOutlet's. Then you can distinguish between them with the following code:
if (collectionView == self.firstCollectionView) { ... }
else if (collectionView == self.secondCollectionView) { ... }
Both firstCollectionView and secondCollectionView must be properties in your View Controller class.
2. Another way is to set tags to them either on Storyboard/Interface Builder or in code with tag property.
So you can for example do this:
self.firstCollectionView.tag = 100;
self.secondCollectionView.tag = 200;
And then again in the cellForItemAtIndexPath method you can distinguish them like:
if (collectionView.tag == 100) { ... }
else if (collectionView.tag == 200) { ... }
Even if you created the collection views in code, you can use the same techniques. Either create properties that point strongly to the collections and compare the pointers or compare them by tags.
The delegate method for cellForItemAtIndexPath also passes in the instance of the collection view it's requesting a cell for. This code snippet is correcting the code example you put in the original post. To take your example, here's how you do this:
- (void)viewDidLoad {
// Initialization of collectionView done previously, set delegates to yourself.
[self.collectionView1 setDelegate:self];
[self.collectionView2 setDelegate:self];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// Setting the cellIdentifier to "hall2" by default, no need to check twice.
NSString *cellIdentifier = #"hall2";
// The collectionView requesting a cell is collectionView2, change the cellIdentifier
if ([collectionView isEqual:self.collectionView2]) {
cellIdentifier = #"hall3";
}
// Since the collectionView we need is already passed, just dequeue and reuse from it.
timeCell *cell = (timeCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
[cell.timeButton setTitle:[[allSimilarMutableArray valueForKey:#"showTime"] objectAtIndex:indexPath.item] forState:UIControlStateNormal];
return cell;
}
I hope this helps you understand how to use multiple collection views with the same delegate.
You can tag the two collection view with different value.
In order to add two UICollectionView in the same page, i user collectionView.tag to identify each of them and decide witch data to pass to each one.
Also, i needed to define different cell sizes for each collection view, but in this method collectionView.tag wasn't working for me. So i had to define a different UICollectionViewLayout to each UICollectionView and then:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if (collectionViewLayout == layout1) {
return CGSizeMake(100,100);
} else {
return CGSizeMake(50, 50);
}
}
So I have a collection view controller that has 3 cells because each cell will have a different layout. My image shows this:
They all have different cell identifiers so in my cellForItemAtIndexPath function I can create the specific cell like:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell;
if(indexPath.row == 0)
{
static NSString *identifier = #"Cell1";
cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
[cell setNeedsLayout];
}
else if(indexPath.row == 1)
{
static NSString *identifier = #"Cell2";
cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
[cell setNeedsLayout];
}
else
{
static NSString *identifier = #"Cell3";
cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
[cell setNeedsLayout];
}
return cell;
}
But when I simulate it, all the cells come out the same size:
Is there a way to force the cell to be the size I have defined or is there a more appropriate way of doing this?
Try this : Custom layout for different cell sizes in UICollectionView
or use this method :
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;