Access custom cell properties in heightForRowAtIndexPath - ios

I have a custom UITableViewCell. I want to access the cells properties i.e. a UILabel etc. I tried inserting the following code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CategorieCell *customCell = (CategorieCell *)[tableView cellForRowAtIndexPath:indexPath];
return ...
}
When I run the app, it crashed without giving me error details. The problem is with the new customCell I'm creating. Is there another way I can access the customCell.m objects?

About the crash, please note that you are using cellForRowAtIndexPath: wich is a method from the UITableViewDatasource that you have to implement, this method calls heightForRowAtIndexPath by default, so it will become a recursive
I assume that you want your custom cell in this method in order to get the height from it.
The best way to achieve this is write a class method on CategorieCell that gives you the height for a cell with certain data.
Other option is extract a method with the code to get the uitableviewcell for example
(CategorieCell*) categorieCellForIndex:(NSIndex)index selected:(BOOL)selected{
...
}

In heightForRowAtIndexPath should never be called cellForRowAtIndexPath.
The first one is called before the second one, and if you need to access to a label (for example to calculate the height of the text) you can normally init a cell.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
static CategorieCell *cell;
if (!cell) {
cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
cell.frame = CGRectMake(0, 0, tableView.frame.size.width-tableView.contentInset.left-tableView.contentInset.right, cell.frame.size.height);
[cell layoutIfNeeded];
}
cell.label.text = myDatasourceText;
CGFloat cellHeight = ....
return cellHeight;
}
NOTE 1:
I used dequeueReusableCellWithIdentifier supposing you are using Interface Builder, otherwise you need to use alloc] initWithStyle:...];
NOTE 2:
As you see I'm setting the frame of the cell. This is needed because otherwise your cell will be (320 x 44) as default. You instead could be in iPhone 6/6+ (i.e. screen width: 414) or in an iPad, and you could need to calculate an height of a label according with his width and his text, and for this reason you need to set the frame of the cell.
NOTE 3:
I'm assuming you have a set of equal cell structure, and for this reason I'm using a static cell, so it will be reused without allocate other useless cells.

Try to register your custom cell class like so:
[self.tableView registerClass:[CategorieCell class] forCellReuseIdentifier:NSStringFromClass([CategorieCell class]);
and then in -tableView:heightForRowAtIndexPath: do something like:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CategorieCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([CategorieCell class)];
}

Related

How to determine UIWebView height based on content inside a variable height UITableView?

I have a UITableView cell that is going to have a variable size depending on it's content (potentially several lines of text).
Since it appears that heightForRowAtIndexPath is called before I layout the cell, I just guess the correct height by calling [NSString sizeWithFont] on my text string. Is there a better way to set the height after I've laid out the text in the cell and have an idea of exactly what size it should be?
My problem is each cell contains a UIWebView with different (statically loaded) content I can't figure out how to calculate the proper height based on the content. Is there a way to do this? I've tried things like this:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
WebViewCell *cell = (WebViewCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath];
[cell setNeedsLayout];
[cell layoutIfNeeded];
return cell.bounds.size.height;
}
The cells themselves are loaded from a nib, which is simply a UITableViewCell containing a UIWebView. (It would also be fine if the cells just adjusted themselves to the largest of the html content, though variable height would be nicer).
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath {
UITableViewCell *cell = [self tableView: tableView cellForRowAtIndexPath: indexPath];
return cell.bounds.size.height;
}

How to get cell in heightForRowAtIndexPath?

I have created custom cells in my app.I want to get the each cell in HeightForRowAtIndexPath.Please tell me how can i get the custom cell in this method.I have tried this code but this causes infinite loop & finally crash the app.
HomeCell *cell=(HomeCell *)[tableView cellForRowAtIndexPath:indexPath];
EDIT:
I Have tried this but it gives me cell height as zero.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"HomeCell";
HomeCell *cell = (HomeCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
float tv_view_height=cell.tv_post.frame.size.height;
float like_count_height=cell.label_like_count.frame.size.height;
float first_comment_height=cell.first_comment.frame.size.height;
float second_comment_height=cell.second_cmment.frame.size.height;
float third_comment_height=cell.third_comment.frame.size.height;
Post *user_post=[arr_post objectAtIndex:indexPath.row];
float comment_count=[user_post.comment_count intValue];
if(comment_count<=0)
{
first_comment_height=0;
second_comment_height=0;
third_comment_height=0;
}
else if(comment_count==1)
{
second_comment_height=0;
third_comment_height=0;
}
else if(comment_count==2)
{
third_comment_height=0;
}
float like_count=[user_post.like_count intValue];
if(like_count<=0)
{
like_count_height=0;
}
float total_height=tv_view_height+like_count_height+first_comment_height+second_comment_height+third_comment_height;
NSLog(#"total heigh is %f'",total_height);
return total_height;
}
Please tell which is the best way?
How to get cell in heightForRowAtIndexPath?
It's impossible, because when -heightForRowAtIndexPath is called, no cells are created yet. You need to understand how the UITableView works:
UITableView asks it's datasource how many sections it will have
-numberOfSectionsInTableView
At this point there are no cells created.
UITableView asks it's datasource how many rows each section will have
-numberOfRowsInSection
At this point there are no cells created.
UITableView asks it's delegate height of each visible row, to know where cells will be located
-heightForRowAtIndexPath
At this point there are no cells created.
UITableView asks it's datasource to give it a cell to display at given index path
-cellForRowAtIndexPath
At this point the cell is created.
The height of each cell you can calculate from data model. You don't need the cell – you already know the frame width that will contain a comment, you know it's content, you know it's font, you know linebreak mode, etc. So, you can calculate height. For example:
CGFloat commentsHeight = 0;
Post *user_post = [arr_post objectAtIndex:indexPath.row];
for (NSString *comment in user_post.comments)
{
CGRect commentrect = [comment boundingRectWithSize:CGSizeMake(self.view.bounds.size.width - 18, FLT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin)
attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:15]}
context:nil];
commentsHeight += commentrect.size.height;
}
And you can calculate height of the other components of cell from its data model.
But now, in 2015, it's not the best way. You really would be better to read the tutorials, which showed #Zil, and do it with Autolayout.
You should declare an array for storing TableView cells in cellForRowAtIndexPath and you can use stored cells in heightForRowAtIndexPath. Lets Try using this.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"HomeCellID";
HomeCell *cell = (HomeCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[[HomeCell alloc] init] autorelease];
}
// Store table view cells in an array
if (![tableViewCells containsObject:cell]) {
[tableViewCells addObject:cell];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([tableViewCellsArray objectAtIndex:indexPath.row]) {
HomeCell *cell = (HomeCell *)[tableViewCells objectAtIndex:indexPath.row];
// Process your Code
}
return yourCalculatedCellHeight;
}
I would recommend you to take the height form a configuration collection on your viewController.
Something like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height;
CellConfiguration * selectedCellConfiguration =[_cellConfigurations objectAtIndex:indexPath.row];
switch (selectedCellConfiguration.type) {
case TheTypeYouNeed:
return TheValueYouNeed
default:
height = 44.0f;
break;
}
return height;
}
You could create a new cell from scratch, simply by HomeCell *sexyCell = [[HomeCell alloc]init];
or dequeue one like you did in cellForRow (tableView.dequeueWithReuseIdentifier:).
Though I advise creating one from scratch and disposing it after (setting it to nil), because if you dequeue it there they'll go in queue and cause heavy memory leaks and end up with many cells for the same indexPath.
What you COULD do is the following :
Create a cell with alloc init
Fill it with the real data
use .layoutsubviews on its view
calculate it's size and apply it to your real cell
What you SHOULD do :
Use auto layout and add all the constraints that are necessary, all your labels will size dynamically. It takes about 3 or 4 hours to get the basics of Auto layout, and about a month of regular use to really get the hang of it with ease.
I strongly strongly strongly suggest you do NOT resize using the frame of objects, most labels and views will resize like they should without having to write any code if you use constraints properly.
Once you have done that, because you have cells of varying heights, is using the DynamicHeight property of the tableview and the slight adjustements that comes with it. You can find
A great tutorial here
The same updated tutorial for swift (more up to date but you'd need to translate)
This amazing StackOverflow answer which you MUST read
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:indexpath.row inSection:0];
Custom Cell *cell = [tableview cellForRowAtIndexPath:indexPath];
By this , you will get each cell in your method

Xcode remove cell with animation programmatically

Hi i have been searching around to find a way to remove a static cell with animation but i have not found a solution to the problem.
I have also tried: [tableView deleteRowsAtIndexPaths:[self.taskArray objectAtIndex:indexPath.row] withRowAnimation:UITableViewRowAnimationFade];
but no success.
You need to hide cell before it is shown, in UITableViewDelegate's tableView:willDisplayCell:forRowAtIndexPath: method. This is the last method in your control where you can manipulate the cell display. It does not remove the space the cell takes, so another thing you can try is to set cell row's height to 0 using the tableView:heightForRowAtIndexPath: method of the same protocol.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if (yourCell) {
return 0;
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
As your tableview is static, you cannot use deleteRowsAtIndexPath. The best option would probably be to migrate your data into a dataSource method for the tableview.
If this is impossible, then this answer ("UITableView set to static cells. Is it possible to hide some of the cells programmatically?") gives that the best method is to use the third party library
StaticDataTableViewController 2.0 (https://github.com/xelvenone/StaticDataTableViewController).
Otherwise you have to use the somewhat hacky method of changing the row height to 0.

Set different height for two custom UITableViewCell

I have two custom UITableViewCell in my table view, that I can't resize properly. The problem is that in IB there is a row height option for the table view, that sets the same height for both cells. I can't just edit the height of the cells in IB, somewhy it doesn't works, the table view's row height overwrites it. I'm using static heights so I tried to set it based on the cell's type, but can't make it work. Is it possible that just my if statement is wrong or I done the whole thing wrong?
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *) indexPath {
InboxCellTableViewCell *cellMessage = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
InboxCell2TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell2" forIndexPath:indexPath];
if(cell) {
[cellMessage layoutIfNeeded];
return 200;
} else {
[cell layoutIfNeeded];
return 155;
}
}
You definitely can do this, and you will do it in -heightForRowAtIndexPath as you suspect.
Instead of attempting to load the cell as you are doing, you should instead use the IndexPath to determine what type of cell is there and then return the proper height for that cell type.
In your cellForRowAtIndexPath method you must have some logic that is already determining the cell type for a given IndexPath, as you return a varying type of Cell from that method already? That same logic can be used to return the appropriate height in the heightForRowAtIndexPath method.

UITableView with Various Custom Cells of differing heights within UIView

I am building a IOS app homepage which basically consists of the following structure -
Which is basically a UIView which contains a nested UIScrollView which inturn contains a TableView with 3 Custom Cells.
I pull data out of a dynamic array and filter it into the relevant cell - all works fine other than two issues I cant work out -
1- The custom cells are different heights in the storyboard but when the app is compiled they are always the same height - is it possible to set an auto height on the UITableView Row? If not can anyone explain how I can apply the correct height to each cell?
2- The TableView / View which wraps the table view need to expand to make all dynamic cells visible - how can I achieve this?
below is my tableview method for reference -
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier =#"CellFeed";
static NSString *CellIdentifierArtNo =#"CellArtRecNo";
static NSString *CellIdentifierBook =#"CellBooking";
UITableViewCell *cell;
feedData *f = [self.HpFeedArray objectAtIndex:indexPath.section];
NSString * ArtPString = #"articleP";
NSString * ArtNoPString = #"article";
NSString * ArtBook = #"booking";
if([f.FeedGroup isEqualToString:ArtPString]){
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
CellHp_RecArticleWithImage *cellImage = (CellHp_RecArticleWithImage *)cell;
cellImage.selectionStyle = UITableViewCellSelectionStyleNone;
cellImage.artTitle.text = f.FeedTitle;
cellImage.artImg.text = f.FeedDesc;
cellImage.artDate.text = f.FeedDate;
cellImage.textLabel.backgroundColor=[UIColor clearColor];
return cellImage;
}
if([f.FeedGroup isEqualToString:ArtBook]){
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierBook
forIndexPath:indexPath];
CellHp_BookingAlert *cellBook = (CellHp_BookingAlert *)cell;
cellBook.selectionStyle = UITableViewCellSelectionStyleNone;
cellBook.HeadlineLbl.text = f.FeedTitle;
cellBook.TextBoxLbl.text = f.FeedDesc;
//cellBook.DateLbl.text = f.FeedDate;
return cellBook;
}
else{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierArtNo
forIndexPath:indexPath];
CellHp_RecArticleNoImage *cellNoImage = (CellHp_RecArticleNoImage *)cell;
cellNoImage.selectionStyle = UITableViewCellSelectionStyleNone;
cellNoImage.artTitle.text = f.FeedTitle;
cellNoImage.artImg.text = f.FeedDesc;
cellNoImage.artDate.text = f.FeedDate;
cellNoImage.textLabel.backgroundColor=[UIColor clearColor];
return cellNoImage;
}
Cheers
It looks like you've got custom UITableViewCell subclasses like CellHp_RecArticleNoImage or CellHp_BookingAlert (may I suggest renaming them to something a little less headache-inducing? ;) ).
In that case, if you only have 3 different cell types, you could do this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
UITableViewCell* cell = [tableView cellForAtIndexPath:indexPath];
if ([cell isKindOfClass:[CellHp_BookingAlert class])
{
return 123.0;
}
else if ([cell isKindOfClass:[CellHp_RecArticleNoImage class])
{
return ...
}
...
}
Or, you could make all your custom classes implement a height method for a cleaner solution and in heightForRowAtIndexPath: you could just get the cell and call its height method.
Re. Question 2, use UIView's sizeToFit method as Tim mentioned.
You need to implement below method to identify the height of cell.
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath
*)indexPath;
You can derive static or dynamic (data driven) cell heights from the storyboard by dequeuing them in heightForRowAtIndexPath according to the procedure outlined here: Retrieve custom prototype cell height from storyboard?
I'm not exactly sure I understand this question, but you can get the contentSize of the table view if you're trying to size the table to fit the content.

Resources