I'm trying to make use of the new Storyboard designer and the ease of drawing UITableView cells instead of programmatically "designing" each row.
A good example of a standard cell is linked here at stack overflow:
iPhone - dequeueReusableCellWithIdentifier usage
Instead of the linked approach of using "[cell textLabel]" I want to use my own labels, buttons and images on top of each row.
Therefore I created several prototype cells/rows and assigned identifiers to them (using Storyboard).
Now: what is the smartest way of accessing each row's "custom" controls/labels? I tried searching for accessing them by ID, but didn't find anything.
My thinking was it should work along this lines:
[[[cell subviews] getObjectByID:#"labelTime"] setText:#"Whatever"];
Is my expectation of the APIs completely wrong or didn't I just find the right API, yet?
Any ideas or recommendations?
For each new custom UITableViewCell that you create in storyboard, you will want to create a new class file which implements UITableViewCell to link it to. Be sure to map all of the controls within your new cell that you laid out in storyboard to instance properties. Then you'll just use it with dequeuing like normal:
YourTableViewCellClass *cell = (YourTableViewCellClass*)[tableView dequeueReusableCellWithIdentifier:#"YourCellIdentifierStringDefinedInStoryBoard"];
// then set the properties for the class.
cell.labelTime = #"whatever";
There are two ways you can get to your custom subviews. The simpler way is using tags. Every view has a tag property which is an integer. You can set the tag in the nib, and set or get it in code. You can search a view tree for a view with a given tag by sending viewWithTag: to the root of the tree. So, for example, you could give your labelTime view the tag 57, and in your code, you'd find the view like this:
UILabel *label = (UILabel *)[cell viewWithTag:57];
The downside of using tags is that you have to keep the tag numbers in sync between your nib and your code. If they get out of sync, you'll either get the wrong view back or you'll get nil (and since you can send messages to nil, the system won't give you an error when that happens). Still, tags are so convenient that it's pretty common to use them like this.
The other way is to create a custom subclass of UITableViewCell with an IBOutlet property for each custom subview. You can hook up the outlets to the subviews in the nib, and access the subviews via the properties in your code:
MyTableViewCell *myCell = (MyTableViewCell *)cell;
UILabel *label = cell.labelTime;
This entails writing a lot more boilerplate than using tags, but it has the advantage that you will get warnings or errors (either at compile-time or when you first try to load the nib) if your nib and your code get out of sync.
Don't be a doofus like I was being. :)
Make sure you set the Identifier value in the Attributes Inspector of the custom cell. Setting the Restoration ID of the custom cell in the Identity Inspector is the wrong way to go, and that's exactly what I did. Major facepalm for myself.
For more implementation details of how to do it, using the methods described by mservidio and rob, check out the section "Designing Our own Prototype Cells" in this tutorial.
Related
So I don't know what the best way to follow MVC is. Similar to the address books app, I want to have a UITableVeiewcell that has the ability to edit notes. I figured I would do that with a UITextView in a UITableViewCell subclass. My subclass has just that as a property, and a label that says "notes". I can see a few use cases that I need to consider,
1) when they are done editing and click outside or hit return.
2) when the text goes beyond the size of the cell I need to resize the cell.
Because my UITextView is in IB, is there a good way to define the delegate methods for the UITextView since my UITableView is in another ViewController subclass? Like how do I pass that information back?
Or, is it better to create my UITableViewCell subclass in code since it's just a couple of items so all my delegate and resizing code is done in the view controller class?
Thanks!
After text field editing was finished, you can store it's value in some dictionary in your controller. You can use cell's indexPath as key in this dictionary. In such way you will not lose your data with dequeue cells.
To resize cell you must call reloadData method and change rowHeight property of entire tableView or implement tableView:heightForRowAtIndexPath: delegate method to set needed row height to current cell.
I haven't use UIKit since iOS 3.1, so the second part of my answer can be out of date, but I hope it will help you =)
Alright. I've done more custom UITableViewCells than I can possibly count over the last three years.
Then comes iOS 5 and I just got a project on my desk where I have to do yet some more.
So the way I used to do this is I would make a custom XIB, drag a UITableViewCell onto the canvas, plug my controls in, set the custom class, do my linkage... then load instantiate the cell in code by looping through the objects after unpacking the XIB.
Did it so many times I had a single Category function to handle the whole thing.
Now all of a sudden in iOS 5 it's serving up big blank white table cells every time I make a custom cell.
Here are the following characteristics of the custom cells being inserted into the table
1) Show completely stark white apart from the "default" UITableViewCell controls (textLabel, etc, will populate and show when I set text to them).
2) isKindOfClass(MyCustomCellClass) reports true
3) Setter methods on custom cell class are functioning, object pointers for set values AND custom UILabels and such all report as non-nil, meaning the cell is actually getting made and properly being instantiated from the XIB
4) Will show offbeat controls like a UIStepper unconditionally for some reason. So yes, if I place a stepper in my custom cell, it shows, but labels and images don't.
As best I can figure, something is obscuring the content view by default, or otherwise the custom controls I am creating are no longer being appropriated to the contentView of the cell anymore (like they used to be), and are instead just being tossed into outer space.
For example, in iOS 4 XIB's, I used to see this when crafting a custom cell (Pulled from Apple's iOS 5 documentation):
But as of this moment, this is what I see when doing the same in an iOS 5 XIB
So note that it's not explicitly showing that little Content View dotted line anymore.
I've really exhausted all of my diagnostic knowhow on this problem. I've tried manually pumping all the custom labels directly into the content view at runtime but even that doesn't work.
I'm looking for any ideas at all.
edit
Code for loading XIB
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"XCCodeViewCell" owner:self options:nil];
cell = codeCell;
self.codeCell = nil;
}
This is currently what it is after simplifying it based on Apple's newer iOS 5 recommendations. The XIB has its owner properly set to the class of "self", and codeCell is linked to the cell properly, with the right class and identifier.
Wow, This one took me a while to test but I think I've got the answer for you...
With Xcode4 in interface builder they added the ability to set up tableViewCells statically in interface builder. This is cool when you want to design tableViews that won't change and you don't want to write them in code. To facilitate this they have set the ability to set the tableViewCell style in IB and see what that looks like. When you design your own cell with your own subviews you select "Custom".
With the iOS 5 developments I found the following; When i loaded a cell from by xib and then programmatically set textLabel.text or another attribute of one of the standard cell styles it seems that the tableViewCell generates that standard view with the default labels in it and overlays your custom view with it. Thus to keep your custom cell subviews you need to not access any of the standard tableCell's properties.
Cool.
Also new in iOS 4 was UINib. You should use UINib for loading tableViewCells from xibs as it has caching and is tonnes faster (all the better for your tableView scrolling). The ARC code looks like this:
header:
#property (nonatomic, strong) UINib * tableCellLoader;
.m file:
-(void)viewDidLoad{
[super viewDidLoad];
self.tableCellLoader = [UINib nibWithNibName:#"MyTableViewCell" bundle:nil];
}
Then in tableView:cellForRowAtIndexPath:
...
if (cell == nil) {
cell = [[self.tableCellLoader instantiateWithOwner:self options:nil] objectAtIndex:0];
}
...
EDIT: updating for new in iOS 5
New in iOS 5 is the ability for the UITableView to keep xibs for certain cell reuse identifiers and then instantiate a new cell of that certain type if there aren't any in the reuse queue.
Check out
– registerNib:forCellReuseIdentifier:
Then when you do
– dequeueReusableCellWithIdentifier:
You're guaranteed to get a UITableViewCell of the specified type back. It saves you doing the whole UINib thing yourself.
UITableViewCells scrolling speed increases dramatically when you do custom drawing, however, Accessibility breaks. How should one add accessibility support to a cell like this?
Old question, but iOS has built in support for this kind of accessibility. Take a look at the UIAccessibilityContainer informal protocol which will allow you to define rects in your view and label them appropriately. Thus, if you draw a big X at 0,0 with a size of 44x44, then you can set the accessibilityLabel for that rect to "Delete".
You'll need to set the relevant accessibilityLabel yourself if you're using custom views to display information (in this case, to draw a table cell). Depending on exactly which view you've taken over drawing for, the label you need might be either the table cell's (for a UITableViewCell subclass) or your custom content view's.
If you're drawing complex information in your custom cells, consider including all that you can reasonably vocalise in the label, separated by commas as discussed in the accessibility guide. What to include is usually common sense but talking to a regular voiceover user can be really helpful, especially regarding what piece of information they want to know first.
I'm a bit in the dark as well on what you are trying to ask. To me, it sounds like you're having trouble accessing methods/objects on your custom cell. When you have a class named CustomCell, use a line like
CustomCell *cell = (CustomCell *)[localTableView dequeueReusableCellWithIdentifier:MyIdentifier];
to create a custom cell.
Suppose your custom cell contains a few labels. You can then access them easily using something like
[cell.aLabel setText:#"Accessed by load"];
When you try to access methods, for example: an IBAction when pressed on a button inside a cell, you should declare those methods in your class CustomCell (and not in your table view's class). After that, link your button's connector to the CustomCell's connector.
Note: this connector won't necessarily be in File's Owner. I'm using XCode 4, and I see 3 objects: File's Owner, First Responder, and Custom Cell. My IBAction is located in Custom Cell, even though I'm used to having it linked to File's Owner.
I hope this was of any help.
I was working with the grouped table view , and i wanted different controls for every row i.e switch control for 1st,radio button for 2nd ,checkbox for 3rd and so on.. how can this be implemented programmatically that is without using interface builder
thanks in advance
CharlieMezak said is right, you need to create in UIControls directly in cellForRowAtIndexPath , and add as subviews to contentView of the cell
For reference see the link below
http://www.e-string.com/content/custom-uitableviewcells-interface-builder
the link specifies the code to create cells programmatically as well as using IB.
Table View Programming Guide for iOS
Read the programing guide, and remember to use different CellIdentifier for each type of cell.
This is a pretty vague question.
Obviously you need to provide the cells to the tableview in its cellForRowAtIndexPath delegate/datasource method. So, either in that method or during the initialization of your view controller, build the UITableViewCell instances that you need, adding the various controls that you want to them as subviews and connecting the controls to your view controller so you can detect when they have been changed. Then just return the appropriate cell in the cellForRowAtIndexPath method.
Personally, I think it's a lot easier to use IB in cases like this. Just create an IBOutlet instance variable for each custom cell you want, and return the right cell in cellForRowAtIndexPath.
I converted my old UITableViewCell from being programmatically created to using Interface Builder and a Xib. When implemented in code and in edit mode, I moved some of the labels in the cell to make room for the delete button. How do I change the layout of the cell in edit mode when implemented as a Xib? Preferably animated. Links or tutorials are certainly welcome!
If it matters, this is for a 3.0 SDK app.
You need to get a reference to the subviews you would like to move. Two ways to do this are:
Tag the views in IB
Use IBOutlets
If you tag the subview you would like to move, you can find it by:
[cell.contentView viewWithTag:kMyTag];
If you choose to use IBOutlets, you should consider creating Cell Controllers for each cell.
A good tutorial on this can be found here:
http://bill.dudney.net/roller/objc/entry/uitableview_from_a_nib_file
Also consider moving your cell logic into the cell controllers and out of the table view controller as mentioned in this tutorial:
http://cocoawithlove.com/2008/12/heterogeneous-cells-in.html