Here's my code:
- (UITableView *)table {
if (!_table) {
_table = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
[_table setDelegate:self];
[_table setDataSource:self];
[_table registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
}
return _table;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
else
[self configureCell:cell forRowAtIndexPath:indexPath];
return cell;
}
The problem is when I registerClass for my table, it assumes that my cell style is UITableViewCellStyleDefault. So that's why detailTextLabel doesn't show up. I tested it.
Comment out the registerClass line doesn't work because I don't have any CellIdentifier for dequeueReusableCell. So it will throw some exceptions.
If I'm not using dequeue, it works, but it not the best practice.
AFAIK, table cell couldn't change its style after init. So how can I make the detailTextLabel show up ?
The problem is when I registerClass for my table, it assumes that my cell style is UITableViewCellStyleDefault. So that's why detailTextLabel doesn't show up
That is correct. The solution is: do not register UITableViewCell as your class. Register a custom UITableViewCell subclass whose sole purpose in life is that it initializes itself to a different style.
For example, register the MyCell class, which you have defined like this:
#interface MyCell:UITableViewCell
#end
#implementation MyCell
-(id)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:UITableViewCellStyleValue2 // or whatever style you want
reuseIdentifier:reuseIdentifier];
return self;
}
#end
Related
I'm currently creating my UITableViewCells programmatically like so:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Home-Cell" forIndexPath:indexPath];
UILabel *newLabel = [[UILabel alloc] initwithframe:cell.frame];
[newLabel setText:self.data[indexPath.row]];
[cell addSubview:newLabel];
return cell;
}
This seems to create a new UILabel each time the cell is reused though, which I definitely don't want. I tried doing the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Home-Cell" forIndexPath:indexPath];
if (cell == nil) {
UILabel *newLabel = [[UILabel alloc] initwithframe:cell.frame];
[cell addSubview:newLabel];
}
[newLabel setText:self.data[indexPath.row]];
return cell;
}
but then the UILabel seems to never be created. Perhaps this is because I'm using prototype cells with Storyboard and thus the cells are never nil?
You have two solutions.
Create a custom table view cell that already has the label.
If you want to add the label in code, don't register a class for the cell. Then the dequeued cell can be nil and you can add the label at that time (like in your 2nd set of code). This also requires using the dequeueReusableCellWithIdentifier method that doesn't also take an indexPath.
You should create a UITableViewCell subclass and add "newLabel" as a property.
The cell is never nil because the method you use to dequeue the table view cell always returns a cell, creating one if it doesn't already exist in the reuse queue.
A better solution would be to create the label in the cell prototype in the storyboard.
This implementation is against MVC architecture where controller managers stuff and do not deal with view. Here, you are trying to add stuff in view from controller. It is suggested to subclass UITableViewCell as below and add your custom UI controls in there
MyTableViewCell.h
#interface MyTableViewCell : UITableViewCell {
}
#property (nonatomic, strong) UILabel *myLabel;
#end
Then you can implement layoutSubviews in your MyTableViewCell.m file to define the look and feel of your cell.
MyTableViewCell.m
- (id)initWithStyle:(UITableViewCellStyle)iStyle reuseIdentifier:(NSString *)iReuseIdentifier {
if ((self = [super initWithStyle:iStyle reuseIdentifier:iReuseIdentifier])) {
self.myLabel = [[UILabel alloc] initWithFrame:<Your_Frame>];
// Set more Label Properties
[self.contentView addSubview:self.myLabel];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
// Override run time properties
}
Finally use your custom cell like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"Home-Cell" forIndexPath:indexPath];
if (cell == nil) {
cell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Home-Cell"];
}
cell.myLabel.text = self.data[indexPath.row];
return cell;
}
As a side note, I hope you know that you get textLabel and detailTextLabel free from default UITableViewCell implementation.
I have this code
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
Song *song = [self.music objectAtIndex:indexPath.row];
cell.textLabel.text = song.title;
cell.detailTextLabel.text = song.artist;
return cell;
I don't use Interface Builder. How I can make this cell to have a subtitle? All I get is a standard cell.
There are two approaches:
The old style approach is to not register any class, NIB or cell prototype, call dequeueReusableCellWithIdentifier without forIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
Song *song = self.music[indexPath.row];
cell.textLabel.text = song.title;
cell.detailTextLabel.text = song.artist;
return cell;
}
As we discussed elsewhere, this assumes that you do not register a class for that reuse identifier.
The alternative is to register your own class in viewDidLoad:
[self.tableView registerClass:[MyCell class] forCellReuseIdentifier:#"Cell"];
and then call dequeueReusableCellWithIdentifier with forIndexPath option, but lose the code that manually tests if it is nil (because it never will be nil):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
Song *song = self.music[indexPath.row];
cell.textLabel.text = song.title;
cell.detailTextLabel.text = song.artist;
NSLog(#"title=%#; artist=%#", song.title, song.artist); // for diagnostic reasons, make sure both are not nil
return cell;
}
This obviously assumes that you've implemented a UITableViewCell subclass that includes the subtitle (note I'm overriding the style):
#interface MyCell : UITableViewCell
#end
#implementation MyCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
return [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}
#end
Personally, I think designing a cell prototype (which automatically registers the reuse identifier and takes care of all of this other stuff) is much easier. Even the old technique of registering a NIB is easier than the above. But if you want to do it entirely programmatically, those are the two approaches.
Try this in your cellForRowAtIndexPath method
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
Hope it helps.
Try this code :
UITableViewCell *cell= [self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell==nil) {
// Using this way you can set the subtitle
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
Song *song = [self.music objectAtIndex:indexPath.row];
cell.textLabel.text = song.title;
cell.detailTextLabel.text = song.artist;
return cell;
I'm using custom cell like that:
PropertyCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
and it's registered as:
[self.tableView registerNib:[UINib nibWithNibName:#"PropertyCell" bundle:nil] forCellReuseIdentifier:#"PropertyCell"];
Class is declared as:
#interface PropertyCell : UITableViewCell <UITextFieldDelegate>
It contains a UITextField in xib and I need to assign a delegate to it on init.
Problem is that:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
is never called in that scenario.
Which kind of initializer is used by that dequeueing mechanism ?
You are going to want to use initWithCoder or awakeFromNib as posted in this question...
initwithstyle:reuseIdentifier: not called
Make sure to init your cell in the UITableViewDataSource method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *PropertyCellIdentifier = #"PropertyCell";
PropertyCell *cell = [tableView dequeueReusableCellWithIdentifier: PropertyCellIdentifier];
if (!cell) {
cell = [[PropertyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: PropertyCellIdentifier];
}
// configure cell
return cell;
}
I have a Class MTTableViewCell : UITableViewCell
The init method in the class is as follows:
Notice that I set the backgroundcolor to purple.
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self)
{
[self setBackgroundColor:[UIColor purpleColor]];
}
return self;
// return [self initMVTableViewCellWithStyle:style reuseIdentifier:reuseIdentifier cellColor:nil];
}
I call the following method from the delegate of the tableview
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* identifier = #"one";
[self.tableView registerClass:[MVTTableViewCell class] forCellReuseIdentifier:identifier];
MVTTableViewCell *cell = [[MVTTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
cell.textLabel.text = [self->datasource objectAtIndex:[indexPath row]];
return cell;
}
However I do not see any change in the color of the table view cells.
What is going wrong ?
When I want to change the background color of my cell i usually use this:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self)
{
[self.contentView setBackgroundColor:[UIColor purpleColor]];
}
return self;
}
I would try moving your call to register class to your viewDidLoad method, and instead of alloc/initing the cell, try dequeueing one from the table. By registering the cell's class for reuse, you're preparing it for recycling by the table. Note: be sure that the cell id that you register is the same as the one that you access in cellForRowAtIndexPath:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[MVTTableViewCell class] forCellReuseIdentifier:#"one"];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"one";
MVTTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
cell.textLabel.text = [self->datasource objectAtIndex:[indexPath row]];
return cell;
}
Unfortunately I'm not on a machine where I can test this an I can't seem to remember the cell call structure in this case (it's late :)) But I would check to see if maybe a different init is being called, otherwise, try setting the background color in cellFor... itself just to troubleshoot. Try setting it on the contentView of the cell as well.
follow this... for custom tableview cell
UITableViewCell Space between Title and Subtitle -iOS
http://www.appcoda.com/customize-table-view-cells-for-uitableview/
I want to make custom uitableviewcellstyle to make comments in my app. I want uitableviewcell with comment text, number of likes, author's name, date etc...
Have you any ideas?
I've created method, but I don't know how realize it.
My code:
- (UITableViewCell *)getCommentTableCellWithTableView:(UITableView *)tableView commentText:(NSString *)commentText numberOfRows:(NSInteger)numberOfRows numberOfLikes:(NSString *)numberOfLikes date:(NSString *)date writer:(NSString *) writerName {
static NSString *CellIdentifier = #"TitleCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
return cell;
}
I'm sorry I can't find a tutorial with clear steps, but you can search some related posts or questions on this site.
Hope the simple code below could help you.
Here is a doc may helps too, take your time to have a look ;)
http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/TableView_iPhone/TableViewCells/TableViewCells.html
New class inherit from UITableViewCell, CustomCell.h:
(Tips:File->New File->Objective-C class->set class name & choose the subclass UITableViewCell)
#interface MapsListViewCell : UITableViewCell
{
// Add iVars that you want.
}
// Some custom methods
CustomCell.m:
// ...
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
// ...
// Some custom methods
- (void)setAuthorName:(NSString *)name
{
// ...
}
TableViewController.m:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CategoriesListViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
CategoriesListViewCell * customCell = (CategoriesListViewCell *)cell;
// Set your data:
[customCell setAuthorName:#"God"];
// ...etc.
return cell;
}
For those of us using the newer (iOS 6 and up) UITableView API for dequeueing cells namelydequeueReusableCellWithIdentifier:forIndexPath this is actually guaranteed to return an instantiated cell so we can't perform the nil check and manually call initWithStyle. Therefore the best solution is to subclass UITableViewCell and manually enforce the style in initialisation.
So as an example if we wanted a cell with the UITableViewCellStyleSubtitle style we would create a custom subclass:
#interface ABCSubtitledTableViewCell : UITableViewCell
#end
#implementation ABCSubtitledTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
return [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}
#end
And then in our viewDidLoad we would register the appropriate class
[tableView registerClass:[ABCSubtitledTableViewCell class] forCellReuseIdentifier:NSStringFromClass([ABCSubtitledTableViewCell class])];
Making our dequeue method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ABCSubtitledTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([ABCSubtitledTableViewCell class]) forIndexPath:indexPath];
cell.textLabel.numberOfLines = 0;
cell.textLabel.text = #"Hello";
cell.detailTextLabel.text = #"World";
return cell;
}