27

How does one obtain the UITableViewCell when within the heightForRowAtIndexPath method, i.e. given the indexPath?

(then I could access the content views I have created to add their heights up)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
  // How to get the UITableViewCell associated with this indexPath?
}

thanks

EDIT: In fact is there really a valid way to do this? When I put some NSLog statements it seems that heightForRowAtIndexPath it called several times before the calls to cellForRowAtIndexPath (which is where I set up the UILabels in the cell)? This kind implies that I may be tried to use a technique that will not work, i.e. I was hoping in heightForRowAtIndexPath to access the already created labels in each cell to get their heights and add them together for the overall cell row height, HOWEVER if they haven't been set up yet (within cellForRowAtIndexPath) then I guess my approach can't really work?

Dalee Davis
  • 981
  • 8
  • 19
Greg
  • 34,042
  • 79
  • 253
  • 454

6 Answers6

24

You can use the tableview's delegate instead of the tableView itself.

id cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];

Check the answer here

UPDATED

In new iOS versions and using correct auto constraints you don't need to reference the cell anymore to calculate the cell's height.

Check here

https://www.raywenderlich.com/129059/self-sizing-table-view-cells

Community
  • 1
  • 1
iosMentalist
  • 3,066
  • 1
  • 30
  • 40
19

This question has no sense because in

heightForRowAtIndexPath

no cells are created yet. Here's how tableView works:

  1. TableView asks it's datasource how many sections it will have. -numberOfSectionsInTableView
  2. Asks it's datasource how many rows each section will have (to know how big scroller should be etc.) -numberOfRowsInSection
  3. Asks it's delegate height of each visible row. To know where cells will be located. - heightForRowAtIndexPath
  4. Lastly it asks datasource to give it a cell to display at given index path -cellForRowAtIndexPath

So you can't access to cells from heightForRowAtIndexPath because with a most likely cell is not created yet.


However in case I misunderstood your question go try:

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
haawa
  • 3,078
  • 1
  • 26
  • 35
14

The obvious answer is to call cellForRowAtIndexPath, but you may have already discovered there are some issues with that. See this question if you haven't already: UITableView flexible/dynamic heightForRowAtIndexPath

For my last project I used a custom subclass of UICell and implemented a method like this. I then called this from table:heightForRowAtIndexPath: (after looking up the content for that row).

+ (CGFloat) heightOfContent: (NSString *)content
{
    CGFloat contentHeight = 
           [content sizeWithFont: DefaultContentLabelFont
               constrainedToSize: CGSizeMake( DefaultCellSize.width, DefaultContentLabelHeight * DefaultContentLabelNumberOfLines )
                   lineBreakMode: UILineBreakModeWordWrap].height;
    return contentHeight + DefaultCellPaddingHeight;
}
Community
  • 1
  • 1
skue
  • 2,057
  • 15
  • 18
  • 6
    Oops, KingofBliss posted while I was creating my answer. Didn't mean my reference to "the obvious answer" to be personal in any way! – skue Mar 10 '11 at 02:42
  • 2
    SizeWithFont seems to be deprecated in iOS 7 how would we do this now? – Martin de Keijzer Sep 12 '13 at 12:51
  • @MartindeKeijzer look here: http://stackoverflow.com/questions/18897896/replacement-for-deprecated-sizewithfont-in-ios-7 – Tobe_Sta Sep 30 '13 at 10:41
4

i would suggest you to calculate the correct height of a row in table:heightForRowAtIndexPath: by using your data structure (Height of text,images,mutliline text etc..).

And change the component height in their -(void) layoutSubviews method.

Jhaliya - Praveen Sharma
  • 31,697
  • 9
  • 72
  • 76
  • I've current got just some UILabels stacked in a UITableViewCell. I'm current setting up the positioning of the UILables within the cell in the cellForRowAtIndexPath method. Is this ok? So I was planning overall to layout labels in cells in cellForRowAtIndexPath, and then set UITableViewCell row height in heightForRowAtIndexPath. Is this OK? – Greg Mar 10 '11 at 05:29
  • @Greg : If your are using more UILables than one , would suggest you to create a CustomCell class which will inherited from UIViewTableCell cell and within the customcell's -(void) layoutSubviews function you can give height to your UILable's as per your requirement, – Jhaliya - Praveen Sharma Mar 10 '11 at 06:02
  • @Greg :I will not recommend you to set the layout of your Labels whether in 'cellForRowAtIndexPath' OR 'heightForRowAtIndexPath' and the best part of my approach that u will get a reusable custom cell component that require less maintenance. – Jhaliya - Praveen Sharma Mar 10 '11 at 06:08
  • thanks for the leads - for the moment I'm just trying to get my head around this approach - might move onto this other approach later (from what I read there are pros & cons for both approaches) – Greg Mar 10 '11 at 09:45
1

If you want to access the cells use tags. But as @Jhaliya has said it is better to calculate the height based on the content of the cell. If your regard is with the position of the cell then I would suggest you to use scroll view and implement the cells yourself wherever you want.

Prajwal Udupa
  • 860
  • 5
  • 28
-19

For iOS8:

override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.estimatedRowHeight = 80
        self.tableView.rowHeight = UITableViewAutomaticDimension
    }

OR

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
            return UITableViewAutomaticDimension

    }

But for iOS7, the key is calculate the height after autolayout,

func calculateHeightForConfiguredSizingCell(cell: GSTableViewCell) -> CGFloat {
        cell.setNeedsLayout()
        cell.layoutIfNeeded()
        let height = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingExpandedSize).height + 1.0
        return height

    }

Note:

1) If multiple lines labels, don't forget set the numberOfLines to 0.

2) Don't forget label.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)

KingofBliss
  • 15,055
  • 6
  • 50
  • 72
  • I'm getting this error when I try this: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyController cellForRowAtIndexPath:]: unrecognized selector sent to instance 0x4d21470' – Greg Mar 10 '11 at 05:58
  • this seems to create a recursive loop repeatedly running through "heightForRowAtIndexPath". In fact putting in some NSLog statements it seems that heightForRowAtIndexPath it called several times before the calls to cellForRowAtIndexPath to create the cells? This kind implies that I may be tried to use a technique that will not work, i.e. I was hoping in heightForRowAtIndexPath to access the already created labels in each cell to get their heights and add them together for the overall cell row height, however if they haven't been set up yet (within cellForRowAtIndexPath)? – Greg Mar 10 '11 at 09:41
  • actually I realize in terms of the specific I guess this answer is correct I think (but it's then the issue how I'm using it in the sense the cells aren't fully setup at that point in time?) - so I should mark as answer in that case – Greg Mar 10 '11 at 10:36
  • 2
    You're correct that they haven't been set up yet and that you can end up in a recursive loop. That's why you may want to fall back to just calculating your cell's height instead. Did you try my solution, below? Should solve your problem. – skue Mar 11 '11 at 05:17
  • this will definitely cause an infinite loop. – Jonathan Jan 07 '13 at 15:33
  • 1
    Why does this answer have so many downvotes? Was it because of a pre-edit mistake or is there still a problem with it? – Suragch Mar 15 '16 at 09:29