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... :)
Related
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];
}
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;
}
}
}
I am using a TableView xib and all the delegates and datasource seem to be running fine.
If I set self.textLabel.text, it displays the generic number of tableviews correctly, but I need to have my custom TableViewCell showing.
I created a HistoryCell.xib that has just a tableviewcell in it.
I created a UITableViewCell class "HistoryCell.h/HistoryCell.m" and it is set as the file owner of HistoryCell.xib.
I connected the UILabels to the HistoryCell.h
UILabel statusLabel
UILabel nameLabel
UILabel timeLabel
In my main ViewController class int he cellForRowAtIndexPath
I am putting in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"historyCellType";
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[HistoryCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.nameLabel.text = #"Donald Duck";
return cell;
}
What am I doing wrong?
Thanks!
You should register the nib like this (probably in viewDidLoad):
[self.tableView registerNib:[UINib nibWithNibName:#"HistoryCell" bundle:nil ] forCellReuseIdentifier:#"historyCellType"];
Then in your cellForRowAtIndexPath method, use this new way where you don't need the if cell == nil clause:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:#"historyCellType" forIndexPath:indexPath];
cell.nameLabel.text = #"Donald Duck";
return cell;
}
You need to deserialize the actual XIB data:
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *cellnib = [[NSBundle mainBundle] loadNibNamed:#"HistoryXIBName" owner:self options:nil];
cell = (HistoryCell *)[cellnib objectAtIndex:0];
}
Otherwise it's just using a "Default" cell.
EDIT: Also, if you are using storyboards, dynamic cell prototypes remove the need to create cells from NIB files (in case that's an option for you.)
EDIT The 2nd:
You can try this as well (this assumes you are using ARC):
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
HistoryCell *aNewCell = [[HistoryCell alloc] initWithNibName:#"HistoryXIBName" bundle:nil];
cell = (HistoryCell *)*aNewCell.view;
}
There's another method using outlets to your cell in the containing view's XIB file that's a bit more involved that I used to use when iOS4 was current. If the edited version isn't' working for you, I'll dig out an old project and remember how I did it.
When you use tableViewCell with xib, while instantiation load from xib.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"historyCellType";
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[NSBundle mainBundle]loadNibNamed:#"HistoryCell"
owner:nil
options:nil]lastObject];
}
cell.nameLabel.text = #"Donald Duck";
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellidentifier=#"cell1";
customcell *cell =
(customcell*)[tableView dequeueReusableCellWithIdentifier:cellidentifier];
if (cell==nil) {
[tableView registerNib:[UINib nibWithNibName:#"Customcell" bundle:nil]
forCellReuseIdentifier:cellidentifier];
cell =
(customcell*)[tableView dequeueReusableCellWithIdentifier:cellidentifier
forIndexPath:[NSIndexPath indexPathForItem:indexPath.row
inSection:indexPath.section]];
}
return cell;
}
Hi I'm new to IOS developement and I created a UITableView which uses custom cells that are created in a nib. Below is my code from my ViewController that is loading the cells however if I scroll up and down 3 times the app crashes because I don't think I'm reusing the cells correctly. I googled around but much of the code/solutions I found seemed to be outdated. My code is below any help is greatly appreciated!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (CustomCell *) currentObject;
break;
}
}
}
cell.TITLE.text = [NSString stringWithFormat:#"\"%#\"", [TITLE objectAtIndex:indexPath.row]];
cell.desc.text = [desc objectAtIndex:indexPath.row];
cell.votes.text = [votes objectAtIndex:indexPath.row];
return cell;
}
change the row
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
to be
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
Go to your CustomCell .xib file in IB, look for the identifier field and set it to CustomCell
You can register the nib for tableView, like :
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
[tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:cellIdentifier];
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
}
//...
return cell;
}
When I run my ios app, only the first cell displays in the TableView, then when clicked the second cell displays. I would like them both to display at the same time, but I cannot figure out this behavior.
Here is the code for my view did load
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ProductCellId";
ProductTableCell *cell =
(ProductTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"ProductTableCell" owner:self options:nil];
cell = self.productCell;
}
Product *product = [products objectAtIndex:indexPath.row];
[cell configureForProduct:product];
return cell;
}
Any help would be much appreciated!
Since you are loading your cell from Interface builder try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ProductTableCell"];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"ProductTableCell" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [topLevelObjects objectAtIndex:0];
}
Product *product = [products objectAtIndex:indexPath.row];
[cell configureForProduct:product];
return cell;
}
Change this:
static NSString *CellIdentifier = #"ProductCellId";
to:
static NSString *CellIdentifier = #"ProductTableCell";
You can find additional information for what you are trying to do in this question: Load cells from XIB files