Actually, I wanted to add multiple xib files to a single UIcollectionview . I have switch case to assign different collectionviewcell for different indexpath. I have not got any clear ideas how to make it possible.
CollectionCell *cell1;
switch (indexPath.row) {
case 0:
[self.Collection registerNib:[UINib nibWithNibName:#"CCollectionCell" bundle:nil] forCellWithReuseIdentifier:#"board"];
cell1 = [collectionView dequeueReusableCellWithReuseIdentifier:#"dashboard" forIndexPath:indexPath];
return cell1;
break;
}
You code style doesn't work because indexPath.row is not fixed param for the swift, so do code like below :
in viewDidLoad
[self.collectionView registerNib:[UINib nibWithNibName:#"CustomCell0" bundle:nil] forCellWithReuseIdentifier:#"MyCell0"];
[self.collectionView registerNib:[UINib nibWithNibName:#"CustomCell1" bundle:nil] forCellWithReuseIdentifier:#"MyCell1"];
// do same for all your six xib
in numberofItems
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 6;
}
in cellForItem
if(indexpath.row == 0){
CustomCell0 *cell0 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell0" forIndexPath:indexPath];
return cell0;
}
else if(indexpath.row == 1){
CustomCell1 *cell1 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell1" forIndexPath:indexPath];
return cell1;
}
:
:
else if(indexpath.row == 4){
CustomCell4 *cell4 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell4" forIndexPath:indexPath];
return cell4;
}
else
{
CustomCell5 *cell5 = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell5" forIndexPath:indexPath];
return cell5;
}
You still need switch-case or if-else to specify which cell you want to load but these are some change that you can update to make you code shorter.
Move registers to viewDidLoad, you only need to call it one time:
-(void)viewDidLoad {
[super viewDidLoad];
[collection registerNib:[UINib nibWithNibName:#"CCollectionCell" bundle:nil] forCellWithReuseIdentifier:#"board"];
}
break will never be called so you can remove it too.
Related
This is my code in cellForItemAtIndexPath, where I want load cell of two collectionView. Here first one is loaded loaded perfectlly but second one is loaded properly.
} else if (collectionView == _collBanner) {
static NSString *cellIdentifier = #"bannerCell";
NSDictionary *dictBanner = [arrImages objectAtIndex:indexPath.row];
BannerCollectionViewCell *cell = (BannerCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
[collectionView registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
[cell setupBannerCell:dictBanner];
return cell;
}
return nil;
}
And my sizeForItemAtIndexPath method is...
} else if (collectionView == _collBanner) {
return CGSizeMake(_collBanner.frame.size.width -5, _collBanner.frame.size.height -2);
} else
return CGSizeMake(0, 0);
}
This line must be in viewDidLoad
[_collBanner registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
The problem is in the order of following two lines:
BannerCollectionViewCell *cell = (BannerCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
[collectionView registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
The first one asks for a cell of BannerCollectionViewCell type, but for the collectionView to be able to dequeue it, the BannerCollectionViewCell has to be registered in the collectionView. Only the second line registers the cell type to the collectionView.
First you have to register the BannerCollectionViewCell type to the collectionView:
[collectionView registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
And only then you can dequeue cells using:
BannerCollectionViewCell *cell = (BannerCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
However, it is enough to register the cell only once, therefore the best way is to register the cell in the viewDidLoad (move the following line from cellForItemAt to viewDidLoad):
[collectionView registerNib:[UINib nibWithNibName:#"BannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellIdentifier];
I have created nib with custom tableViewCell.
Created Class TableViewCellSimple for it with black label color.
Now I want to subclass this cell and get red color of label.
So, I create subclass of it TableViewCellRedColor and override init method.
- (void)setup
{
[super setup];
self.titleLabel.textColor = [UIColor k_mainRed];
}
In my VC, I register this 2 cells:
[self.tableView registerNib:[UINib nibWithNibName:#"TableViewCellSimple" bundle:nil] forCellReuseIdentifier:kCellIdentifier_ TableViewCellSimple];
[self.tableView registerNib:[UINib nibWithNibName:#"TableViewCellRedColor" bundle:nil] forCellReuseIdentifier:kCellIdentifier_ TableViewCellRedColor];
And then I creating cells:
switch (indexPath.row) {
case 0:
{
TableViewCellSimple *cell = (TableViewCellSimple *)[self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier_ TableViewCellSimple];
cell.titleLabel.text = NSLocalizedString(#"Clear All Messages", nil);
return cell;
}
break;
case 1:
{
TableViewCellRedColor *cell = (TableViewCellRedColor *)[self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier_ TableViewCellRedColor];
cell.titleLabel.text = NSLocalizedString(#"Leave Chat and Event", nil);
return cell;
}
break;
But I did not get red color. I debug my code and overridden method did not called.
Why?
I'm working with Xcode 6.1.1, and I have a table view controller with static cells having 4 sections.
Section 0: contains two rows, each with 2 labels
Section 1: contains 7 image views
Section 2: contains 1 row with 1 label
Section 3: contains a variable number or rows each containing 2 image
views
I want to load all cells in the table view controller with data.
I gave each different row a reuse identifier (5 reuse identifiers in total), and I also created a class for each of the different kind of cells (5 classes)
I created outlets in the classes, and linked them in the storyboard each to its label/image view.
However I don't know how to proceed next.
If I implement the table view data source functions, I'm getting the correct number of cells, however they are all blank.
Here's how I'm creating the cells:
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
if (indexPath.section == 0 && indexPath.row == 0) {
static NSString *CellIdentifier = #"MyCell1";
MyTableViewCell1 *cell = (MyTableViewCell1*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MyTableViewCell1 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
} else {
//create other cells here
}
cell.label1.text=#"testing 123";
return cell;
}
However, I'm always getting cells with default style (my labels or image views are not appearing)
What am I missing?? What code should I write in the custom table view cell classes?
EDIT: After gavin's suggestion, I modified the delegate function to use the dequeueReusableCellWithIdentifier:forIndexPath
I also added: [self.tableView registerClass:[MyTableViewCell1 class] forCellReuseIdentifier:#"MyCell1"] to my viewdidload method.
Here's my final code:
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[MyTableViewCell1 class] forCellReuseIdentifier:#"MyCell1"];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 3 ) {
return 1;
} else {
return [super tableView:tableView numberOfRowsInSection:section];
}
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
if (indexPath.section == 3) {
// make dynamic row's cell
static NSString *CellIdentifier = #"MyCell1";
MyTableViewCell1 *cell = (MyTableViewCell1*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[cell configureCellWithValues:#"17" andV2:#"13"];
return cell;
} else {
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 3) {
MyTableViewCell1 *c = (MyTableViewCell1 *) cell;
NSLog(#"willdisplay cell with values %#, %#",c.i1, c.i2);
[c.image1 setImage:[UIImage imageNamed:#"2"]];
}
}
And here's my custom cell's class:
#implementation MyTableViewCell1
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void) configureCellWithValues: (NSString*) v1 andV2:(NSString*) v2 {
self.i1=v1;
self.i2=v2;
self.image1.image = [UIImage imageNamed:v1];
self.image2.image = [UIImage imageNamed:v2];
}
#end
The cells in section 3 are still not showing the images (not even the imageviews)
Look like you're using the old method of tableView reusable cell dequeueing - the new function accepts an indexPath as well as the cell identifier; it also now guarantees to return a cell (so no need for a nil check).
Here's your delegate function cleaned up:
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
if (indexPath.section == 0 && indexPath.row == 0) {
static NSString *CellIdentifier = #"MyCell1";
MyTableViewCell1 *cell = (MyTableViewCell1*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
} else {
//create other cells here
}
cell.label1.text=#"testing 123";
return cell;
}
Another tip would be to encapsulate your setting of the label values into each individual cell subclass, e.g. add a method called configure to MyTableViewCell1 that sets the label values to what you want displayed.
It seems that we can't generate custom static cells and try to access their outlets and change them (because their static) please correct me if i'm wrong because I couldn't access them at all.
I've solved my Problem by changing the TableView Type to Dynamic Cells, i didn't put any prototype cells in the tableview and I have created 3 different Cell Classes (with their nibs)
I have registered the nib files with the tableview by adding this to the viewdidload method:
[self.tableView registerNib:[UINib nibWithNibName:#"MyCellType1" bundle:nil] forCellReuseIdentifier:#"CellType1"];
[self.tableView registerNib:[UINib nibWithNibName:#"MyCellType2" bundle:nil] forCellReuseIdentifier:#"CellType2"];
[self.tableView registerNib:[UINib nibWithNibName:#"MyCellType3" bundle:nil] forCellReuseIdentifier:#"CellType3"];
then i fully customized my tableview methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
switch (section) {
case 0:
return 2;
break;
case 1:
return 1;
case 2:
return [self.myarray count];
default:
break;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.section) {
case 0: {
MyCellType1 *cell = (MyCellType1 *) [tableView dequeueReusableCellWithIdentifier:#"CellType1" forIndexPath:indexPath];
//this section always has 2 rows
if (indexPath.row==0) {
cell.lblTitle.text = #"ID";
cell.lblValue.text = [NSString stringWithFormat:#"%i",1277];
} else {
cell.lblTitle.text = #"Date";
cell.lblValue.text = #"02/03/2015";
}
return cell;
}
break;
case 1: {
MyCellType2 *cell = (MyCellType2 *)[tableView dequeueReusableCellWithIdentifier:#"CellType2" forIndexPath:indexPath];
cell.image1.image = [UIImage imageNamed:#"3"];
cell.image2.image = [UIImage imageNamed:#"4"];
return cell;
}
case 2: {
MyCellType3 *cell = (MyCellType3 *)[tableView dequeueReusableCellWithIdentifier:#"CellType3" forIndexPath:indexPath];
cell.lblName.text = #"New Row";
return cell;
}
default:
break;
}
return nil;
}
How do i add different componenets to different cells in a tableview. Please note that this is a static table and i have only 4 cells.
The first cell will have an UIImageView.
The other 3 cells will just have labels or textfieilds.
How can i add these components.
Note: This is a storyboard based application and i have added
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell;
if(indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell0"];
cell.profImageView.image=[UIImage imageNamed:#"m.jpg"];
return cell;
}
else if(indexPath.row == 1)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
cell.lbl.text=#"Hey";
return cell;
}
else if(indexPath.row == 2)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell2"];
cell.lbl.text=#"Hey 2";
return cell;
}
return cell;
}
You are having 4 rows in your data source but you are only providing cell object for 3 rows. The last return statement will execute for indexPath.row==3 and you have not initialised it. Just initialise it for indexPath.row==3 and you are good to go.
MyTableViewCell *cell;
if(indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell0"];
cell.profImageView.image=[UIImage imageNamed:#"m.jpg"];
}
else if(indexPath.row == 1)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
cell.lbl.text=#"Hey";
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell2"];
cell.lbl.text=#"Hey 2";
}
return cell;
The reason that you don't give the default return value to your function and it asks for "If everything goes wrong what will i return?". So you may fix your codes like above and you can try to make like below with the switch - case.
TableViewCell *cell;
switch (indexPath.row) {
case 0:{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell0"];
cell.imageView.image=[UIImage imageNamed:#"m.jpg"];
}break;
case 1:{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
cell.myLabel.text=#"Hey";
}break;
case 2:{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell2"];
cell.myLabel.text=#"Hey 2";
}break;
default:{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell0"];
cell.imageView.image=[UIImage imageNamed:#"m.jpg"];
}
break;
}
return cell;
In above switch-case you may call which cell you want in default statement.
In a specific row I apply the default UITableViewCell class with a text label and an accessory button. When the accessory button is clicked, the cell is expanded and I want to change the UITableViewCell to a custom subclass I have created. However even if the cell is expanded, it won't switch to the custom subclass. Any ideas what to fix?
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat result;
switch ([indexPath row])
{
case 2:
{
if ([indexPath isEqual:expandedRow]) {
return 100;
} else {
return 42;
}
}
return result;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier;
NSString *CellIdentifierexp;
UITableViewCell *cell;
if (cell == nil) {
if (indexPath.row == 2) {
if ([indexPath isEqual:expandedRow]) {
cell = [[ExpandedCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifierexp];
}else{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
switch ([indexPath row])
{
case 2:
{
if ([indexPath isEqual:expandedRow]) {
NSLog(#"bike");
ExpandedCell *expandedcell = (ExpandedCell *)cell;
[expandedcell.text setText:self.descr];
NSArray *indexPathArray=[NSArray arrayWithObject:indexPath];
[self.tableview reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone];
} else {
cell.textLabel.text = #"Description";
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.textColor = UIColorFromRGB(0x2d5b3b);
// accessory type image
UIImage *image = [UIImage imageNamed:#"greenarrow.jpg"]; //or wherever you take your image from
UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(0,0, image.size.width, image.size.height)];
[button setBackgroundImage:image forState:UIControlStateNormal];
[button addTarget:self action:#selector(accessoryButtonTapped:withEvent:) forControlEvents:UIControlEventTouchDown];
button.userInteractionEnabled = YES;
cell.accessoryView = button;
}
break;
}
return cell;
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
switch ([indexPath row])
{
case 2:
{
NSLog(#"Detail Disclosure Tapped");
expandedRow = indexPath;
[tableview beginUpdates];
[tableview endUpdates];
}
}
}
- (void) accessoryButtonTapped: (UIControl *) button withEvent: (UIEvent *) event
{
NSIndexPath * indexPath = [self.tableview indexPathForRowAtPoint: [[[event touchesForView: button] anyObject] locationInView: tableview]];
if ( indexPath == nil )
return;
[self.tableview.delegate tableView: self.tableview accessoryButtonTappedForRowWithIndexPath: indexPath];
}
Wow, you're doing something terribly wrong in here:
ExpandedCell *expandedcell = (ExpandedCell *)cell;
[expandedcell.text setText:self.descr];
NSArray *indexPathArray=[NSArray arrayWithObject:indexPath];
[self.tableview reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone];
What you should do is slightly different. On a button tap you just call the [self.tableview reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; then in the cellForRowAtIndexPath you should return the custom cell of your subclass in the method if the indexPath matches. No need to update the tableView there.
And need I say that this looks like a very very strange switch statement to me:
switch ([indexPath row])
{
case 2:
{
NSLog(#"Detail Disclosure Tapped");
expandedRow = indexPath;
[tableview beginUpdates];
[tableview endUpdates];
}
}
I would simply put it like this:
if (indexPath.row == 2){
NSLog(#"Detail Disclosure Tapped");
expandedRow = indexPath;
[tableview beginUpdates];
[self.tableview reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableview endUpdates];
}
Running the code
expandedRow = indexPath;
[tableview beginUpdates];
[tableview endUpdates];
when the accessory button is tapped will only ask the table view to update the row heights, it won't actually request a new cell for any row, so no cell type change will happen (until you scroll the row off screen and then back on again).
So, you need to actually reload the selected row, not just begin and end updates.
this here...
UITableViewCell *cell;
if (cell == nil) {
Local vars dont init to nil , they start as garbage, maybe nil , maybe not.
Either way you probably are not making it into the branch.
You are going to want to dequeue a cell from the table depending on whether its an expanded row or not
UITableViewCell *cell = nil;
if(thisIsAnExpandedRow) {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierexp];
if(!cell) {
cell = [[ExpandedCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifierexp];
}
}
else {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
}