Reusable TableViewCell in Interface Builder WITH changeable labels? - iphone

How do I make a reusable TableViewCell in Interface Builder with changeable labels?
Is this even possible? From what I understand apple has been giving custom TableViewCell in Interface Builder some love lately, so this should be possible?
Ps. I know there are a lot of questions with answers about TableViewCell in IB, but I couldn't find anyone that made labels work.

You can change anything in a cell that is being re-used. To customize labels that you create in IB, you should set their tags in IB itself & fetch the label using the same tag.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
MyCell* cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[MyCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
//Do anything here with the labels. Even add or remove them.
(UILabel*) label1 = (UILabel*)[cell viewWithTag:1];
return cell;
}

I used to do it he same way as in accepted answer, but I've always felt using tags like I'm using "go to" in Pascal. Feels dirty. But maybe it's just me, tags work just fine.
There's an alternative way though. Subclass a UITableViewCell, create an IBOutlet property, connect in IB, and reference your property in cellForRowAtIndexPath: code. Like so:
interface MyCustomCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *myAwesomeLabel;
#end
Don't forget to set you cell's class to MyCustomCell in IB.
After that you can connect your property in IB directly like so
And in your Table View Data Source now you can access this property
#import "MyCustomCell.h"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell *cell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell) {
cell.myAwesomeLabel.text = #"Hello, World!";
}
return cell;
}
Using tags is error-prone and might turn into a mess very quickly if you use a lot of them.

Related

IPhone Storyboard custom cell disappears when scrolling down

I have just finished a project where I use a custom cell for my TableView in Storyboard.
The problem is that when i scroll down the content in each cell is gone, which in my case is
two Labels.
This is the code I use to present each cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCell";
MessageCell *cell = (MessageCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Message *messageForRow = (Message *)[messages objectAtIndex:[indexPath row]];
[cell.messageLabel setText:[messageForRow message]];
[cell.senderLabel setText:[messageForRow sender]];
return cell;
}
I have specified the right cellidentifier in storyboard and linked the Class to my
custom cell class.
What can be wrong? If there is any needed information I have missed to present, please
tell me.
Best regard
Robert
Could you check by logging that this method is called when scrolling?
I solved it by myself, the problem did not lie within the update method.
By mistake I used the weak signature for the properties in my Message class.
#property (nonatomic, weak) NSString *sender;
I solved it by using the strong signature instead.
#property (nonatomic, strong) NSString *sender;
This was a great lesson because I didn't fully understand the concept
of strong and weak.

How to control a customized UITableViewCell within a UITableView Implemented within a UIViewController?

In my app I wish to have a UIViewController that will hold a UITableView in it. In this UITableView I wish to have a customized UITableViewCell (i.e. I wish to define my own elements in this CELL - image, labels and buttons - as seen in the image below). And... I want to create them in the Storyboard.
Now, setting the elements in the Storyboard is easy.
I understand how to connect the UITableView and set it in the UIViewController (including the delegates in the .h file and using the basic table delegate methods).
What I'm not clear about, is how to connect and control the customized UITableViewCell and its outlets. Can I create the Outlets and Actions within the UIViewController .h and .m files? Do I need to create a separated UITableViewCell.h/.m files and call on them in the cellForRowAtIndexPath method?
Can anyone suggest what's the best approach for my needs?
UPDATE:
Here is the code I used in cellForRowAtIndexPath while using the separated MyCell.h/m file option. This code is written in the ViewController.m file, where the UITableView is implemented.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ContentCell";
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//MyCell is the Objective-C Class I created to manage the table cells attributes.
//#"ContentCell" is what I had entered in the Storyboard>>UITableViewCell as the Cell Identifier.
if (cell == nil) {
cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
//Here is the place I'm not clear about - Am I supposed to init the cell in a different way? If so, how?
}
cell.contentNameLabel.text = [self.dataArray objectAtIndex: [indexPath row]];
// this is the test I had done to check if the new "MyCell" object is actually getting what I would expect it to get. well... the text gets updated in the relevant label, so i guess it gets it
return cell;
}
When running the app, using the debugger break point, I can see that the code always skips the "if (cell == nil)" and never enters the code where the new MyCell object supposes to be allocated and initiated. Any idea what may I be doing wrong?
Correct, create separate UITableViewCell.h/.m files to match your custom UITableViewCell class and call on them in your cellForRowAtIndexPath method.
In your storyboard, set the class of your custom UITableViewCell to your custom class (e.g. CustomTableCell).
Your custom UITableViewCell class would contain IBOutlets which you would wire up in your storyboard, here is an example:
CustomTableCell.h:
#import "CustomStuff.h" // A custom data class, for this example
#interface CustomTableCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *titleLabel;
- (void)configureForCustomStuff:(CustomStuff *)stuff;
#end
CustomTableCell.m:
#import "CustomTableCell.h"
#implementation CustomTableCell
#synthesize titleLabel;
#pragma mark - Configure the table view cell
- (void)configureForCustomStuff:(CustomStuff *)stuff
{
// Set your outlets here, e.g.
self.titleLabel.text = stuff.title;
}
#end
Then, in your cellForRowAtIndexPath method, configure your cell:
CustomTableCell *cell = (CustomTableCell *)[tableView dequeueReusableCellWithIdentifier:#"CustomCellID"];
// Your custom data here
CustomStuff *customStuff = <YOUR CUSTOM STUFF>
[cell configureForCustomStuff:customStuff];

Using UITableViewCell in a UITableView

I'm a little confused with something. I'm trying to create a custom cell and I want to use the interface builder way.
The normal way I create a table is to have the table as:
.h
#interface AssessList : UIViewController {
IBOutlet UITableView *tblAssessList;
}
#property(nonatomic, retain) UITableView *tblAssessList;
#end
.m
- (NSInteger)
numberOfSectionsInTableView:(UITableView *)tableView {
return groupArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return totalArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = #"I am the text....";
return cell;
}
Now i've created a new class for the cell and I think I understand how to put that in. But can I leave the .h as
#interface AssessList : UIViewController
or does the class/nib with the full table on it have to be a UITableViewController?
Tom
does the class/nib with the full table on it have to be a
UITableViewController?
No. A UITableViewController is just a convenience UIViewController subclass which has a UITableView and is already setup as its delegate/datasource (it is declared as conforming to the UITableViewDelegate and UITableViewDatasource protocols), it also has pre-filled method implementations for these protocols in the template implementation file which Xcode generates for you. You can just as well do all of this yourself, I often do.
You should however make an IBOutlet for your UITableViewCell so that you can load it from the nib file (see the Loading Custom Table-View Cells From Nib Files in the Table View Programming Guide).
If you want to do in the Interface Builder Way, then create an xib (view xib). Drag and drop a UITableViewCell object from the obj palette. Customize it as you wish. In the tableView:cellForRowAtIndexPath: method, do this:
UITableViewCell * aCell = [tableview dequeueReusableCellWithIdentifier:#"SomeIdentifier"];
if (aCell == nil)
{
NSArray *arr = [[NSBundle mainBundle] loadNibNamed:#"CustomCellNibName" owner:self options:nil];
for (NSObject *anObj in arr) {
if([anObj isKindOfClass:[UITableViewCell class]]) {
aCell = (UITableViewCell *)anObj;
}
}
}
The identifier for the tableviewcell can be set in the IB.
I guess it should be sub class of UItableViewCell
i.e.
#interface AssessList : UITableViewCell
When you want a custom tableview cell you will also need a subclass of UITableViewCell..
A tutorial can be found on this blog
Keep in mind that quite a few things can be done without creating a custom cell, this includes adding the switch to make your tableview look like the one from settings.app, to the way the iPod displays songs.
In the assessList Class you are using the custom cell created in otherviewController (UITableViewCell subclass) so there is no need to change this line
#interface AssessList : UIViewController
Note:- the otherviewController should be a subclass of UITableViewCell

Creating custom UITableViewCell's within a Storyboard

Wanting to create a static menu (IOS 5) and attempting to create custom cells within the storyboard to then load onto the grouped tableview.
I've created the outlet
#property(nonatomic,strong) IBOutlet UITableViewCell *labelCell;
The ViewController class is set to the proper TableViewController and I've connected the custom cell to this outlet.
I also have the delegate and datasource set up.
I've got
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return self.labelCell;
}
I'm sure there is a ton wrong with this, but I'm just trying to display one cell and go from there. There does not seem to be any examples of doing custom cells within the IB through the storyboard. I can still use the old way of creating a xib file and loading it in the mainBundle but I just want to stay up to date I guess.
but with what I have above i get a crash when I load this view controller. SIGABRT
Here is what I've learned about how you get cells for your table when using the storyboard. When you drag a UITableView into your view, it comes with a prototype cell already set as a subview. To use this prototype cell, set a unique reuse identifier in the attributes inspector, and then use the same identifier to dequeue the cell in your cellForRowAtIndexPath: method. I leave out the code for creating a cell from scratch if the dequeue call returns nil; I don't think it can happen. So just dequeue the cell, configure it with the usual UITableViewCell methods, and return it.
But you can also create custom subclasses of UITableViewCell. Just set the class name in the storyboard's class identity inspector, and drag whatever elements you want from the Objects palette into your cell. Then create IBOutlet properties for them in your subclass's code files, and hook them up to the cell in the storyboard in the usual way. This is so much better than having to do it all in code!
And finally, you can have more than one kind of cell in your table. Just drag UITableViewCell objects from the palette into the table, and give each one a unique reuse identifier in the attributes inspector. In your cellForRowAtIndexPath: method, choose the type of each cell and you can have a very flexible table view.
If you have set your UITableView to be using 'Static Cells' in the storyboard, you don't need to implement any of the UITableViewDataSource methods and you can modify the cell directly in Interface Builder. For a single label cell, select the cell and change it's type to 'Basic'. You can now edit the cell just like you would any other view object.
This tutorial was helpful to me. You can reference whatever object you need through the tag.
In the Storyboard drag on a UIImageView or UILabel etc. and set the tag to 100 (whatever you want) then in your - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath use the tag to reference it.
Here is the example code in the tutorial, just remember to set the tags in the storyboard:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Display recipe in the table cell
Recipe *recipe = [recipes objectAtIndex:indexPath.row];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.image = [UIImage imageNamed:recipe.imageFile];
UILabel *recipeNameLabel = (UILabel *)[cell viewWithTag:101];
recipeNameLabel.text = recipe.name;
UILabel *recipeDetailLabel = (UILabel *)[cell viewWithTag:102];
recipeDetailLabel.text = recipe.detail;
return cell;
}

How to display multiple columns in a UITableView?

I want to display multiple columns in a UITableView.
For Example:
TableView
FName LName Age
----- ----- ---
Abby Michale 34
I think the correct way of doing this is UICollectionView. Started with UITableView and finally failed at some point due to unexpected behavior while trying to implement scrolling both left-right and up-down.
Please check this awesome post for a complete and up-to-date solution:
http://www.brightec.co.uk/blog/uicollectionview-using-horizontal-and-vertical-scrolling-sticky-rows-and-columns
Result will be like this:
You can define a custom cell in IB, which will contain 3 labels and in function:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *DetailCellIdentifier = #"DetailCell";
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:DetailCellIdentifier];
if (cell == nil) {
NSArray *cellObjects = [[NSBundle mainBundle] loadNibNamed:#"DetailCell" owner:self options:nil];
cell = (UITableViewCell*) [cellObjects objectAtIndex:0];
}
// setup your cell
}
when you define the cell in IB give each label a tag, so when you need to put a text there you can retrieve it by tag like this:
label = (UILabel *)[cell viewWithTag:NAME_TAG];
label.text = myObject.name;
and repeat this with other 2 labels. The tag is a unique number.
Put this code instead //setup your cell comment
I have created UIGridView. I believe your problem can be solved using the same technique.
You can learn the source code of UIGridView. The code is really short.
Bit late to the party, but we've open sourced our fully featured table component:
https://github.com/flexicious/iOSDataGrid
Some screenshots:
http://www.ioscomponents.com/Home/IOSDataGrid
Feel free to use!
Create a custom UIView subclass containing, say, three UILabel elements as subviews. Then set the cell's contentView property to this custom view.
add three labels as sub viewsinto uitableview cell's content.then assign apprrpriate values to it
eg:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
//frame should be set accordingly(means should be framed accordingly).
UILabel *l1=[[UILabel alloc]initWithFrame:CGRectMake(5, 5, 100,100)];
UILabel *l2=[[UILabel alloc]initWithFrame:CGRectMake(110,10,100,80)];
UILabel *l3=[[UILabel alloc]initWithFrame:CGRectMake(115,60,100,50)];
[cell.contentView addSubview:l1];
[cell.contentView addSubview:l2];
[cell.contentView addSubview:l3];
return cell;
}