Is that possible to create multiple cells in one xib? - ios

I found it can create different cells with different xibs, but I want to know is possible to create different cell in one xib? If possible, what should I can do this?
Here is the code, I know it is wrong code, so can you guys help me to fix it?
- (void)viewDidLoad {
[super viewDidLoad];
[imageTableView registerNib:[UINib nibWithNibName:#"ImageTableViewCell" bundle:nil] forCellReuseIdentifier:#"oneImageTableViewCell"];
[imageTableView registerNib:[UINib nibWithNibName:#"ImageTableViewCell" bundle:nil] forCellReuseIdentifier:#"twoImageTableViewCell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *identifier1 = #"oneImageTableViewCell";
NSString *identifier2 = #"twoImageTableViewCell";
if (indexPath.row % 2 == 0) {
ImageTableViewCell *cell = [imageTableView dequeueReusableCellWithIdentifier:identifier1 forIndexPath:indexPath];
return cell;
} else {
ImageTableViewCell *cell = [imageTableView dequeueReusableCellWithIdentifier:identifier2 forIndexPath:indexPath];
return cell;
}
}

My first idea would be to not do it. But if I had to do it, I guess I'd try building cells by using the old style dequeue, and, to build the initial pool of reusable cells, by manually extracting them from the nib.
So, don't do any cell nib or cell class registration, then in cellForRowAtIndexPath...
NSString *identifier;
NSInteger index;
if (indexPath.row % 2 == 0) {
identifier = #"oneImageTableViewCell";
index = 0;
} else {
identifier = #"twoImageTableViewCell";
index = 1;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"ImageTableViewCell" owner:self options:nil];
cell = topLevelObjects[index];
}
return cell;

Related

UITableViewCell changes its label value every time I scroll

I have a reusableCell that has a label for which the values are supplied by an array. But the values of the label and the constraints change every time, my cellForRowAtIndexPath code looks like
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row % 2 == 0)
{
isReceived =TRUE;
}
else{
isReceived = FALSE;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"id" forIndexPath:indexPath];
ChatMessageCellTableViewCell *messageCell = (ChatMessageCellTableViewCell*) cell;
if(messageCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ChatMessageCellTableViewCell" owner:self options:nil];
messageCell = [nib objectAtIndex:0];
}
else{
[[messageCell formLabel]setText:messages[indexPath.row]];
[messageCell setSelectionStyle:UITableViewCellSelectionStyleNone];
} // this else part is just to make sure that the if has a else part as I saw many people it will work , but in my case it didn't help.
[[self tableView] setEstimatedRowHeight:50.0];
[self.tableView setRowHeight:UITableViewAutomaticDimension];
return messageCell;
}
When I scroll the table, Values are changing. I tried many different way, but could not find a solution and I am so confused that I had to post my question.
Thank You
I know it's bad practice to answer your own post, but I hope this helps someone
I was able to avoid those changes by changing the method cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = (indexPath.row % 2 == 0 ? #"EvenCell" : #"OddCell"); //using different identifier for every cell did the trick I guess
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
ChatMessageCellTableViewCell *messageCell = (ChatMessageCellTableViewCell*) cell; ;
if (messageCell == nil) {
messageCell = [[ChatMessageCellTableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];
if(indexPath.row % 2 == 0)
{
isReceived =TRUE;
}
else{
isReceived = FALSE;
}
}
[[messageCell formLabel]setText:messages[indexPath.row]];
[messageCell setSelectionStyle:UITableViewCellSelectionStyleNone];
[[self tableView] setEstimatedRowHeight:50.0];
[self.tableView setRowHeight:UITableViewAutomaticDimension];
return messageCell;
}
I have commented the change's which I have made in order to prevent changes in the cell's while scrolling.
Thanks for all the support :)
There is a wrong logic in your code, your code is only assign data for reused cell but not for new created cell. You should move the code in else bracket out like this.
ChatMessageCellTableViewCell *messageCell = (ChatMessageCellTableViewCell*) cell;
if(messageCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ChatMessageCellTableViewCell" owner:self options:nil];
messageCell = [nib objectAtIndex:0];
}
[[messageCell formLabel]setText:messages[indexPath.row]];
[messageCell setSelectionStyle:UITableViewCellSelectionStyleNone];
I'm not familiar with Obj-C, but this may helpful to you.
if youHaveTitleText {
cell.title.text = data.displayText
} else {
cell.title.text = ""
}

UITableview with two different custom cells overlapping while scrolling

I have a UITableView with two different custom cells. One will show normal text message and other with some text and image. I am able to use two different custom cells in cellForRowAtIndexPath and able to see two different cells like below
But whenever i scroll the tableview then the cells are overlapping like below.
Below is my code
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
//minimum size of your cell, it should be single line of label if you are not clear min. then return UITableViewAutomaticDimension;
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
id cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell isKindOfClass:[TicketTableViewCell class]]) {
return 171;
} else {
return UITableViewAutomaticDimension;
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [chatHistoryArr count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *msgTypeStr = [msgTypeArr objectAtIndex:indexPath.row];
if ([msgTypeStr isEqualToString:#"msg"]) {
static NSString *simpleTableIdentifier = #"ChatConversationTableViewCell";
ChatConversationTableViewCell *cell = (ChatConversationTableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ChatConversationTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.chatmsgLabel.text = [chatHistoryArr objectAtIndex:indexPath.row];
cell.timeAndDateMsgLabel.text = [timeAndDateMsgArr objectAtIndex:indexPath.row];
return cell;
}
else{
static NSString *simpleTableIdentifier = #"TicketTableViewCell";
TicketTableViewCell *cell = (TicketTableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TicketTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.tktMsgTxtView.text = [chatHistoryArr objectAtIndex:indexPath.row];
cell.ticketDateAndTimeLbl.text =[timeAndDateMsgArr objectAtIndex:indexPath.row];
return cell;
}
}
No issues in showing data or showing different cells, only problem is overlapping. I have already tried the available solutions but no luck. Below is one of them.
adding the below code in cellForRowAtIndexPath but no use.
for(UIView *view in cell.contentView.subviews){
if ([view isKindOfClass:[UIView class]]) {
[view removeFromSuperview];
}
}
Tried a lot to fix the issue but no luck. Any help will be really appreciated.
Change your code of tableViewCell height
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *msgTypeStr = [msgTypeArr objectAtIndex:indexPath.row];
if ([msgTypeStr isEqualToString:#"msg"]) {
return UITableViewAutomaticDimension;
} else {
return 171;
}
}
It will resolve your overlap issue.
Try this once
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell %d",indexPath.row];
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
if (cell == nil){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

ios tableViewCell.xib file generate more than one cell

- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"FriendTableViewCell" bundle:nil] forCellReuseIdentifier:#"FIDCELL"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FriendTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"FIDCELL"];
return cell;
}
This code block work but when i add new cell in FriendTableViewCell.xib not work actually i can not call new cell. How can i call this cell or this is possible ? If this question is not clear i can add image...
**
i try to call different cell from same .xib
**
Error:
I found solution i generate new .xib and call when page load both of them
[self.tableView registerNib:[UINib nibWithNibName:#"FriendTableViewCell" bundle:nil] forCellReuseIdentifier:#"FIDCELL"];
[self.tableView registerNib:[UINib nibWithNibName:#"Cell2" bundle:nil] forCellReuseIdentifier:#"FIDCELL2"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellID = #"";
if (indexPath.row % 2 == 0) {
cellID = #"FIDCELL";
} else {
cellID = #"FIDCELL2";
}
FriendTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
// Configure the cell...
cell.nameLabel.text = self.namesArray[indexPath.row];
cell.photoImageView.image = [UIImage imageNamed:self.photoNameArray[indexPath.row]];
return cell;
}
This code part totally work.
Okey so first of all , every cell should have its unique identifier so if the first cell have an identifier called "FIDCELL" the second one should have another one called "FIDCELL2" for example , and remove the following line from your viewDidLoad :
[self.tableView registerNib:[UINib nibWithNibName:#"FriendTableViewCell" bundle:nil] forCellReuseIdentifier:#"FIDCELL"];
and add this to cellForRowAtIndexPath
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell * cell ;
if(condtion1)
{
cell = [tableView dequeueReusableCellWithIdentifier:firstCellIdentfier];
}
else if(condtion2)
{
cell = [tableView dequeueReusableCellWithIdentifier:secondCellIdentfier];
}
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:yourNibName owner:self options:nil];
if(condtion1)
{
//0 is the index of the first cell in the nib
cell = [nib objectAtIndex:0];
}
else if(condtion2)
{
//1 is the index of the second cell in the nib .
cell = [nib objectAtIndex:1] ;
}
}
//do other work
return cell ;
}
where condtion1 and and condtion2 is the conditions that will determine which cell will be chosen .

Is it possible to have two different UiTableViewCells in one UiTableView? [duplicate]

This question already has answers here:
2 different types of custom UITableViewCells in UITableView
(3 answers)
Closed 9 years ago.
I'm having an issue and would like to know if what I am trying to do is even possible.
I have a ViewController that has a UITableView as a subview. I then loaded a custom cell and it worked fine. However, I needed another custom cell in the same tableview - this second cell has a separate nib as well.
Is this possible?
Two different custom cells in on section in a UITableView?
I did try something like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
// Space Cell
if (indexPath.row== 0) {
CellSpace *cell = (CellSpace *) [tableViewdequeueReusableCellWithIdentifier:CellIdentifier2];
return cell;
}
// Content cell
else {
CellView *cell = (CellView *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
// Configure cell
return cell;
}
}
However it seems the else statement is never fired and I normally get a crash saying the method returned nil.
UPDATE
I used the advice and code here and came up with this:
#pragma mark - UITableView Delegate Methods
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 160;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 22;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier1 = #"UsernameCell";
static NSString *CellIdentifier2 = #"PasswordCell";
if(indexPath.row == 0) {
BBUsernameRegistrationCell *cell = (BBUsernameRegistrationCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier1 owner:self options:nil]; // set properties
cell = nib[0];
}
// set properties
return cell;
}
// Content cell
else {
BBPasswordTableViewCell *cell = (BBPasswordTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier2 owner:self options:nil]; // set properties
cell = nib[0];
}
// set properties
return cell;
}
}
However I only see the first Cell in my tableview. If I switch the cells around the second one loads. But not both at the same time. Does anyone have any idea why?
Yes, it is possible..
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
// Space Cell
if (indexPath.row== 0) {
CellSpace *cell = (CellSpace *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell == nil) {
cell = [[CellSpace alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1];
// set properties
}
// set properties
return cell;
}
// Content cell
else {
CellView *cell = (CellView *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell == nil) {
cell = [[CellView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
// set properties
}
// set properties
return cell;
}
}
in your custom cell, do something like this in initWithStyle method:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CellView" owner:self options:nil];
for (id currentObj in topLevelObjects ) {
if ([currentObj isKindOfClass:[CellView class]]) {
self = (CellView*) currentObj;
}
}
return self;
}
Yes it is possible. But before use this dequeueReusableCellWithIdentifier:. Just register your cell and corresponding nib files.
code as..
-(void)initiateCellRegisteration
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
[self.tableView registerClass:[ContentCell class] forCellReuseIdentifier:CellIdentifier2];
[self.tableView registerNib:[UINib nibWithNibName:CellIdentifier2 bundle:nil] forCellReuseIdentifier:CellIdentifier2];
[self.tableView registerClass:[SpaceCell class] forCellReuseIdentifier:CellIdentifier1];
[self.tableView registerNib:[UINib nibWithNibName:CellIdentifier1 bundle:nil] forCellReuseIdentifier:CellIdentifier1];
}
Call this method in viewDidLoad
If you are using the cell nib then you need little tricky way to get your cell nib like
static NSString *CellIdentifier = #"ProductCell";
IVProductCell *cell = (IVProductCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray* objects = [[NSBundle mainBundle] loadNibNamed:#"IVProductCell" owner:nil options:nil];
for (id currentObject in objects) {
if ([currentObject isKindOfClass:[IVProductCell class]]){
cell = (IVProductCell*) currentObject;
}
}
}

Custom cells issue in iOS 5

I've a custom UITableViewCell subclass and I've read that this is supposed to be the correct way of loading custom cells for iOS 5:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [tv dequeueReusableCellWithIdentifier:#"customCell"];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"customCell"];
// Configure cell
cell.nameLabel.text = self.customClass.name;
}
return cell;
}
But the label text is not shown when I run the app. However, I also tried this way:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:#"customCell"];
if (cell == nil) {
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:nil options:nil];
for (UIView *view in views) {
if([view isKindOfClass:[UITableViewCell class]])
{
cell = (CustomCell *)view;
}
}
// Configure cell
((CustomCell *)cell).nameLabel.text = self.customClass.name;
}
return cell;
}
This way the label is displayed, but any reuseIdentifier is set in loadNibName: method. What the best way of loading custom cells should be? I need to support iOS 5+. Could the first approach not be working because I'd to configure cell's labels and styles in initWithStyle: method and not in the table view's method?
Thanks!
The error in your code is that cell.nameLabel.text is only set in the if (cell == nil) { ... } case and not generally.
The easiest ways to load custom cells are
Use registerNib:forCellReuseIdentifier: if the cell is defined in a nib file, or
use registerClass:forCellReuseIdentifier: if the cell is created programmatically, or
use a Storyboard and define "CustomCell" as "Prototype Cell" for the table view.
For example (in viewDidLoad):
[self.tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:#"customCell"];
Then dequeueReusableCellWithIdentifier
will always return a cell, so that cellForRowAtIndexPath simplifies to
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [tv dequeueReusableCellWithIdentifier:#"customCell"];
cell.nameLabel.text = self.customClass.name;
return cell;
}
Just use this code and try.
static NSString *cellIdentifier=#"cell";
YourCustomCell *cell = (YourCustomCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
NSString *customeCellName = [NSString stringWithFormat:#"%#",[YourCustomCell class]];
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:customeCellName owner:self options:nil];
for (id currentObject in topLevelObjects)
{
if ([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (YourCustomCell *) currentObject;
break;
}
}
}
cell.nameLabel.text = self.customClass.name; // Make sure self.customclass.name have value.
return cell;
Use this code (NewCustomCell is your Custom UITableViewCell class name)...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NewCustomCell *cell = (NewCustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib=[[NSBundle mainBundle]loadNibNamed:#"NewCustomCell" owner:self options:nil];
cell=[nib objectAtIndex:0];
}
return cell;
}
Happy coding... :)

Resources