I previously used the following code for changing the size of my cells which use a custom UITableViewCell:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 61;
}
However I've created a new one on a different view and the above code is never being called.
The UITableViewCell is actually a control on a more generic view however all the other similar methods cellForRowAtIndexPath etc are
Make sure you've set your class as the delegate for the table view, in addition to the dataSource. They are two separate protocols, and this is easy to overlook.
Seems I needed this as well
- (UITableViewCell *) getCellContentView:(NSString *)cellIdentifier {
CGRect CellFrame = CGRectMake(0, 0, 300, 60);
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CellFrame reuseIdentifier:cellIdentifier] autorelease];
return cell;
}
Also, you can accomplish the same thing (I think) in IB by tweaking the values on the UITableView (not the UITableViewCell).
heightForRowAtIndexPath is only a UITableView delegate method, not a UITableViewCell method.
So you'd have that code in your delegate class, not in the table cell code.
Related
I'm creating a Settings View for my app, and in that view is a UITableView. I'm creating custom cells to meet my needs, but I'm having issues - only the last cell is getting [layoutSubviews]. Am I doing something wrong?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//int type = (indexPath.row == 0?1:0);
//if(indexPath.row == 6) type = 2;
NSLog(#"row %i created", indexPath.row);
TableCell *cell = [[TableCell alloc] initWithType:indexPath.row];
cell.textLabel.text = #"Test cell";
return cell;
}
And in my custom cell:
#implementation TableCell
UIImageView *shadowView;
int row;
- (id) initWithType:(int)type {
row = type;
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
self.backgroundColor = [UIColor clearColor];
self.backgroundView = [[UIView alloc] init];
UIImage *shadowImage = [UIImage imageNamed:#"CellShadow"];
shadowImage = [shadowImage resizableImageWithCapInsets:UIEdgeInsetsMake(14, 14, 14, 14)];
shadowView = [[UIImageView alloc] initWithImage:shadowImage];
[self.contentView addSubview:shadowView];
//[self.contentView sendSubviewToBack:shadowView];
NSLog(#"agreed, row %i created", row);
[self layoutSubviews];
return self;
}
- (void) layoutSubviews {
NSLog(#"row: %i", row);
[super layoutSubviews];
shadowView.frame = CGRectMake(
0, 0,
self.contentView.frame.size.width,
self.contentView.frame.size.height
);
}
#end
Continuously, only the last cell #6, is reported when I rotate, or when layoutSubviews should be called. Any suggestions?
Do not call layoutSubviews directly. Use [self setNeedsLayout] or [self layoutIfNeeded]. But do not call these at all in the cell's init method.
Also, do not call [[TableCell alloc] initWithType:indexPath.row]; directly, either. Instead, use...
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath
Once you've built that cell, you can tell it it's row, but be aware that the cells get recycled as the table scrolls, so you must update that value on every call to cellForRowAtIndexPath.
The cells ought to get layout again (without you making any calls direct or indirect) when the table view is resized.
See the tableview doc here.
You should never call layoutSubviews directly, it will be called automatically by iOS once the cell is ready to display. You should also deque the cell as #danh is recommending. If you're not very comfortable with all this, then I'd really recommend you have a look at the free Sensible TableView framework, which automates creating these kind of settings views (I create mine in a couple of lines, really).
The issue was of my own poor code. Using cell.backgroundView helped a lot here.
Never Call layoutSubviews by yourself. It will be called when ever frames of subview in cell are changed. Even if just change the text of labels in your custom cell wont call layoutSubviews. Ue the deque of cells for reusing for better performance. As it wont allocate cell every time. And in you code looks like has lot of memory issues since cell allocated wont be released and new cell is created.
I have created two types of prototype cells in storyboard. The dimension of one of them have been customized to accomodate UIButton object. However when the cells are created, they have the standard height. I can see the UIButton object but it gets truncated because of the cell height.
Why are the newly created cells different from the prototype cells?
The relevant section of the code is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
if(cell == nil)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"PictureSelectionCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
pictureButtonProperty = (UIButton *) [cell viewWithTag:1];
}
}
Going forward, what are my options for creating the cell of the width (or dimensions) defined in the storyboard? Programmatically, I will be able to achieve this by creating a CGRect object with the specified dimensions and then create a cell using initWithFrame. However, I would like to avoid doing things manually.
Thanks for your response.
first of all you can always set it with code
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return YOUR_ROW_HEIGHT;
}
other way if you choose your UITableView if the storyboard, under the size inspector change the Row Height.
In my application i need to display multiple images in a UITableView,so i've already searched a lot in the web for the proper way to load large images to UITableViewCells,to be more clearly i'll divide the procedure that my app execute:
Download images asynchronous;
Save them to NSHomeDirectory();
=> Thins part is working perfectly.
The problem is,how to display the images in the UITableViewCell,i've already tried to add UIImageView's to the cell contentView but the scrolling performance were a bit affected,i've searched on Apple guides and i believe the correct way is adding UIImageView's to the cell and loading the images from NSHomeDirectory(),so:
What's the best way to customize a UITableViewCell and add the UIImageView's(302x302px) to it?
To get the best scroll performance, you must draw the content of the UITableViewCell yourself.
Loren Brichter, the author of the Tweetie app (now the official Twitter app), wrote a very famous blog post on this. Sadly, this blog post has been deleted.
This article may help you, though. It explains the fast scrolling, it has examples and it has a video to a presentation from Loren Brichter.
Basically, what you want to do is to subclass UITableViewCell and override the drawRect:method. To show an image, you would do something like the following:
- (void)drawRect:(CGRect)rect
{
[myImage drawAtPoint:CGPointMake(10, 10)];
}
This way you avoid to layout a lot of subviews.
I have the same question.
I'm doing the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString* CustomCellIdentifier = #"CustomCellIdentifier";
CustomCell* cell = [tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CustomCellIdentifier];
}
// add subview to cell
if (cell.customView == NULL) {
cell.customView = [[CustomView alloc] initWithFrame:cell.frame];
[cell.contentView addSubview:cell.customView];
}
// bind cell data
return cell;
}
Firstly, you need to create a custom cells for UITableView & keep going through following points.
set height of each row to 302 pixels as
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 302.0;
}
Use following code to create UIImageView at each cell of table
-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:#"cell"];
const NSInteger IMAGE_VIEW_TAG=1001;
UIImageView *imageView;
if(cell==nil)
{
cell=[[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"] autorelease];
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
imageView =[[[UIImageView alloc] initWithFrame:CGRectMake(10, 0, 302, 302)] autorelease];
imageView.tag=IMAGE_VIEW_TAG;
imageView.contentMode=UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:imageView];
}
imageView=(UIImageView*)[cell.contentView viewWithTag:IMAGE_VIEW_TAG];
[imageView setImage:[UIImage imageNamed:#"image.png"];
return cell;
}
set number of rows you want to display
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
dont forget to add TableView delegate and data source , UITableViewDelegate and UITableViewDataSource
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 do i change the location of the text AND show the FULL string in UITableView?
Here is a screen shot of what I have, once you look at it you will know what I mean. Thanks
My App http://img188.imageshack.us/img188/9926/chucknhelp.tif
You can do it without subclassing UITableViewCell.
In the method tableView:cellForRowAtIndexPath:, create a basic UITableViewCell and change the properties of the UILabel contained in this cell. Change the maximum number of lines to fit more text in your cell.
Unfortunately, the label of the cell is not accessible by properties, so you need to fetch it with the subviews property.
Of course this uses an implementation detail of UITableViewCell, so it might break with future releases of the SDK. Use with care.
Here is an example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"YourCellId"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"YourCellId"] autorelease];
cell.font = [UIFont systemFontOfSize:16];
UILabel* cellLabel = [cell.contentView.subviews objectAtIndex:0];
[cellLabel setNumberOfLines:3];
}
cell.text = #"Your text";
return cell;
}
Update:
To set the row height to fit the text, you can do the following:
1. Set the cell height to fit the text.
You need something like this:
CGSize textSize = [text sizeWithFont:font
constrainedToSize:CGSizeMake(313, 1000)
lineBreakMode:UILineBreakModeWordWrap];
cell.frame = CGRectMake(0.0f, 0.0f, 320.0, textSize.height);
2. Return the cell height in the tableView:heightForRowAtIndexPath: method.
For example like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [self tableView:(UITableView*)self.view cellForRowAtIndexPath:indexPath];
CGRect cellFrame = cell.frame;
return cellFrame.size.height;
}
Subclass UITableViewCell, and in the subclass's loadView method, create a UILabel inside its contentView. Set this label to have the appropriate wrapping and location.
Adam has it right. For a little more detail (as well as a method that scrolls lightning fast) you can check out this entry on atebits.com that bypasses the UILabel approach entirely.
Loren Brichter's UITableViewCell subclassing example
You can also look at the TableViewSuite example from developer.apple.com It contains 5 different examples, in increasing complexity, for building custom TableViews. The last example is structurally very similar to the tutorial on atebits.com.
Lecture 8 of the Stanford iPhone course is also all about Scroll and TableViews, and has some examples of subclassing UITableViewCell.
iPhone Course