8

I have a dynamic list of items, each item could have different teamplate/layout (and height). And one those item types could have an internal list of items to select from, regularly 5-6 rows, each has different height.

If I try to describe it further, in my scenario I have one tableview (#slave) inside tableviewcells (#master-cell) of another tableview (#master). Moreover cells (#slave-cell) in my #slave tableview could have different height as well. So I need to layout my #slave to have #master automatically calc and update its size.

enter image description here

I have the issue with the inner table (#slave). In case of auto-layout, to fit all the cell space, the table will be collapsed unlike UILabel or other controls. So what I need here is to get the projected size of #slave table and set the height of the #slave = content height of the #slave.

I found similar post and it works if all rows have the same height but I'm using custom rows with dynamic height so the tableView.contentSize.Height gives me invalid result (basically just multiply rowNumbers * estimatedRowHeight, you can see it on the screenshot, master item #3 has 4 inner cells). Even after calling #slave.reloadData I couldn't get that size.

What is the proper way to build that kind of UI?

Source code with a test project attached (Xamarin.iOS)

Community
  • 1
  • 1
Mando
  • 11,414
  • 17
  • 86
  • 167
  • why do you need tableView inside tableview? – rushisangani Apr 23 '16 at 04:59
  • I think you're looking for `optional func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat` – user212514 Apr 23 '16 at 05:05
  • @iOSEnthusiatic it's design requirements, I have a dynamic list of items, each item could have different layout (and height). And one those items could have internal list of items to select from, regularly 5-6 rows, each has different height. – Mando Apr 23 '16 at 06:39
  • Why would you need multiple tableviews for this? Can't you just use sections to divide your tableView and insert cells with different heights (or even automatically calculated heights using UITableViewAutomaticDimension)? – Sander Saelmans Apr 23 '16 at 07:38
  • @SanderSaelmans could you please suggest how can I use sections in my scenario. Do you recommend go with whole new section for this particular data item instead of just a single cell? – Mando Apr 25 '16 at 18:24
  • you could use sections to achieve what you want to do, you should have as many sections as master items and in each section you should have the sub items @AlexeyStrakh – Klinkert0728 Apr 25 '16 at 21:52
  • now I got the idea with sections. Unfortunately my items source consists of different type of items so in the proposed approach I'll have to go with a section for other items as well, which is unexpected design change. I'm just trying to introduce new item type with custom layout (table inside). @Klinkert0728 – Mando Apr 25 '16 at 22:35
  • @AlexeyStrakh if i understood well, you need a different design in the cells of the section? – Klinkert0728 Apr 26 '16 at 02:18
  • Yes, different design for different cell types. In my example above there's only one type, and have others. – Mando Apr 26 '16 at 05:23
  • So you could have different prototype cells to match each design you want @AlexeyStrakh – Klinkert0728 Apr 26 '16 at 13:55
  • yes of course, you can see my answer maybe it can help you @AlexeyStrakh – Klinkert0728 Apr 29 '16 at 13:13
  • @AlexeyStrakh i had a similar scenario when i put a collection view inside tableviewcell i did make it work but when i scrolled back and forth as fast as i can i got a crash beacuse the delegate where not getting called fast enough and the delegate returned a nil cell, i hope you don't get it.If you get the same crash i think you have to somehow use sections to manage this scenario. – Ahmad Ishfaq May 02 '16 at 14:34
  • @AhmadIshfaq thank you for you concerns about the crash, I'll take it into account, most likely will do a one line text elements in my inner table which will allow me to define the inner table height properly and have no issues with auto-layout and auto cell height calculation – Mando May 02 '16 at 19:04

8 Answers8

4

I just ran into the same problem a few days ago,and tried to work it around.

The #master-cell works like a childViewController,it's the delegate datasource of the #slave TableViewController.But you cann't have a childViewController in the UITableViewcell.

Customize UITableViewCell to hold necessary property and acts as #slave TableViewController's delegate datasource,and configure #slave-cell's height and data.

The real problem is the height for #master-cell,

  1. If your data is simple and static,you can compute the height in advance,and return it in method func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat of the ViewController.
  2. Otherwise,add a method to #master-cell which return the height for the whole cell when its property is set.And create a proxy #master-cell to compute the height and return it :

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
      let cell   = CustomUITableViewCell();
      let model  = self.getModel(indexPath)
      cell.model = model
      let height = cell.requiredHeight()
      return height;
    }    
    

    It's complex and expensive,but it works.

wj2061
  • 6,778
  • 3
  • 36
  • 62
  • It doesn't solve my issue but at least helped me to move forward. In may case I don't have issues with the height of the #master-cell. I'm using auto-layout and it defines the height automatically pretty well, once I know the height of all inner elements. The issue here is that I don't know the height of my inner table view because of its dynamic content. – Mando May 02 '16 at 19:02
  • @AlexeyStrakh I know this is an old post but did you manage to solve this at the end? Im having exactly the same issue and I cant find any information on the internet and Ive tried everything I found but still not working. – Emil Jun 15 '17 at 14:14
  • @Emil I used the method 1 to achieve the effect. In my case , I only need to return 4 different cell height in according to the data source.The #slave-table, don't need to be shown all at once, otherwise, you can just use a lot of common views. – wj2061 Jun 15 '17 at 14:28
  • @wj2061 thank you for your reply. My problem is that both of my tableview need to have dynamic cell sizes and also the slave-tableview should be no scrollable. The master-tableview doesn't have any problem for calculating the cell size of all the other cells, but when calculating the size of the cell that contains the slave-table fails. The slave-table has a height = 0. I even tried adding a iboulet constraint to slave-table and setting this but nothing – Emil Jun 15 '17 at 14:35
3

I think you do not have need of take UITableView inside UITableView. You can take more than one section in UITableView. And use different cellReuseIdentifier. This way your goal will be achieved.

Payal Maniyar
  • 4,293
  • 3
  • 25
  • 51
1

For such a layout ios provide section in tableview, for master items use SectionView(there is delegate method for sectionView -> in which you can provide view for a section) and as different section may have different type of row so make rows according your need and return them according to section.

  • I have a slightly different solution, where I couldn't use section because of other cell types. – Mando May 02 '16 at 18:58
1

Perhaps it is because I do not know the background of you project or what you are trying to accomplish, but tableViews inside of tableVIew cells sounds unnecessarily trivial. Rather than using a master tableView with #slave tableViews, it would be cleaner to just break things out by section in a single tableView as stated in a previous answer. There are UITableViewDelegate methods designed to streamline this for you!

pennyloaf
  • 90
  • 7
1

first you have to get string's height then the height have to give in below tableView delegate

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return stringHeight;

}

it is working for me.

  • the issue for inner table is that I'm unable to get height for inner strings because at the moment I need to say the height of host cell my slave table is not bound to data. Even if I bound it, my inner cells are not created at the moment I need to calc the height – Mando May 02 '16 at 18:55
1

I'm using Xcode 8.3.2 and Swift3.1.

I had the same requirement, have tried all, nothing worked for me.

Finally, UIStackView is what worked for me.

In a tableviewcell, I have added a UIStackView(Verticle), keep adding sub cells to that UIStackView. And it automatically increased the cell height.

Check the following to add UIStackView programmatically.

Add views in UIStackView programmatically

Ashok
  • 5,585
  • 5
  • 52
  • 80
  • This works, but then of course you don't get the `UITableView` functionality from it's delegate methods, and that I was hoping to get too. – turingtested Oct 22 '18 at 09:07
  • I was expecting the same, but unfortunately, it's not feasible as of now. – Ashok Oct 30 '18 at 15:42
0

If you Use Different Sections and Rows use the below format, its working for me,

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0) {
        return 121;
    }
    if(indexPath.section==1)
    {
        return 81;
    }

    if (indexPath.section%2 == 0 && indexPath.row == 1) {
        return 161;
    }

    if (indexPath.section%2 != 0 && indexPath.row == 0) {
        return 81;
    }

    if (indexPath.section==16 && indexPath.row==0) {
        return 161;
    }
    else
    {
        return 44;
    }
}

i have Template code, different section and row, its each row have different sizes, so i have give this type of code, if you get idea see the above code then its helpful for you,

or

If you change the height for Content text size use the below code, its calculate the content size then change the height(UILabel) size, its working for me

-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ListModel *model = [ListArray objectAtIndex:indexPath.row];

    CGRect labelRect = [model.content boundingRectWithSize:CGSizeMake(tableView.frame.size.width - 90 - 15, 0)
                        options:NSStringDrawingUsesLineFragmentOrigin
                        attributes:@{
                                     NSFontAttributeName : [UIFont fontWithName:@"Arial" size:14.0]
                                     }
                        context:nil];

    CGFloat heightOfCell = labelRect.size.height + 60;

    if(heightOfCell > 106)
        return heightOfCell;

    return 106;
}

hope its helpful

Iyyappan Ravi
  • 3,205
  • 2
  • 16
  • 30
-1

yes of course you can have as many prototypes cells as you want for example check this piece of code:

     override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        if indexPath.section == 0 {

        let cell =  tableView.dequeueReusableCellWithIdentifier("TodayWeatherCell", forIndexPath: indexPath) as! SITodayWeatherTableViewCell

        cell.setupCell(upCommingWeather)
        cell.aboutCityUpdateTableViewClousure = {
            self.tableView.reloadData()
        }

        return cell
    }else {

        let cell = tableView.dequeueReusableCellWithIdentifier("cityDetailCell", forIndexPath: indexPath) as! SICityDetailTableViewCell
        let detail = detailCity[indexPath.row]
        cell.setupCityDetail(detail)

        return cell
        // Configure the cell...
    }
  }

There are two different cells in one single UITableView.

Hope it helps.

Klinkert0728
  • 326
  • 1
  • 4
  • 14