0

View Heirarchy

So basically, I want to embed a UITableView inside UITableViewCell.

I used UIStackView to use its AutoLayout power!

Anyway, each row of "Inner UITableView" will consist of a fixed sized UIImageView and a UILabel of lines = 0 (i.e. not fixed)

UIStackView(horizontal) -> UIImageView + UILabel

Requirements:

  • The size of each row/cell for InnerTableView should be dynamic due to random text being provided from the server. Thus making the whole InnerUITableView's height to automaticDimension
  • The text for the UILabel above InnerUITableView is also dynamic. (thus makes sense to use UIStackView in the first place)

Note: The Main UITableView consist of multiple cells of different types (this is basically a BotChatBot)

Also: estimatedHeight can be around 40 points.

Problem:

The InnerTableView being dynamically sized leads to its cellForRowAt method not being called for once, thus not allowing UIStackView to increase its length due to no change in contentSize.

In order to fix the above problem, I tried:

  • Setting up initial height constraint for UITableVIew to 10(some random number), estimatedRowHight for InnerTableView being 50, thus setting up height of UITableView as tableViewInsideCellHeightConstraint?.constant = tableViewInsideCell.contentSize.height which somehow gives me some room but it's still not reliable when height for a row exceeds estimated height of 40

The problem

P.S layoutIfNeeded() were triggered for TableView, StackView and ParentCell

I also have another way of solving the above problem:

  1. Using estimated height, multiply the constant(estimatedHeight) by number of rows to be displayed i.e. list size
  2. Change heightConstraint for Inner UITableView with the calculated one,
  3. With each iteration, calculate the total "REQUIRED" height (using +=visibleCells[i].frame.height) of UITableView (as each iteration will provide the size of the cell(content size)
  4. Update the height constraint of Inner UITableView
    if heightForTableView == nil {
        if indexPath.row == listDict!.count - 1 {
          var heightOfTableView: CGFloat = 0.0
          let cells = tableView.visibleCells
          for visibleCells in cells {
            heightOfTableView += visibleCells.frame.height
          }
          let newHeight = heightOfTableView + cell.frame.height
          reloadMe(newHeight)
        }
      }

The above fix leads to visible jerk in the UI :[

Question:

Is there any concrete solution to the above problem? I tried searching it over and over again.. can't really find any strong fix!

Daksh Gargas
  • 3,498
  • 2
  • 23
  • 37
  • So yes the problem is that tableviews themselves are not supposed to have dynamic heights. Their contents scroll. They are suppose to be fixed and then their children grow as needed. Can you show an example of the final UI you are trying to achieve (maybe a mock up or example). I have a feeling it might be easier to just go a different way with this entirely – Simon McLoughlin May 14 '19 at 08:22

2 Answers2

0

When you call api for data in subTableView you can try like below :

self.tvCell?.table.reloadData() //tv cell is my Parent TableViewCell
self.table.beginUpdates() //Parent TableView
self.table.endUpdates() // Parent TableView

It is working fine for me i hope it will help you.

Virani Vivek
  • 888
  • 1
  • 8
  • 22
  • The data is being received from the socket, thus an Asynchronous process and I'm not aware of the action... also, I can't reload my parent tableView cell reason being a chatBot thus already contains list of multiple cells. Thanks though :) – Daksh Gargas May 14 '19 at 09:43
  • updating parentTableView will probably scroll the user to the bottom of the screen.. right? – Daksh Gargas May 14 '19 at 09:45
  • no you can see https://stackoverflow.com/questions/28244475/reloaddata-of-uitableview-with-dynamic-cell-heights-causes-jumpy-scrolling question it help you for dynamic height without scroll – Virani Vivek May 14 '19 at 09:47
0

Ok so you are building a chat app. That changes a few of my suggestions.

So to answer your question as it stands, you could follow something like this: Replacement for deprecated sizeWithFont: in iOS 7? calculating the size of the text with sizeWithAttributes:. Adding up all the label heights (working out if the image will be bigger) and using that to try calculate a fixed height for the tableview, then it would display the list entirely. This isn't really an ideal case for tableview.

Personally I would have a look at the way slack handles this. Rather than having the options inside the text bubble, you could have each option appear as a new bubble or cell on its own after the message, or have a bunch of buttons in a single cell.

Here's an example of standbot (from their website) showing a cell with a collection of buttons, possibly in a stack-view or a scrollview. This might be a much easier way to achieve it rather than having a tableview inside a tableview enter image description here

Simon McLoughlin
  • 8,293
  • 5
  • 32
  • 56
  • Yes yes, I completely agree with your solution, I had the same thought (calculating the height) but that will definitely hit the performance if the user is scrolling the app (I can cache it, even store it in the model though). And I totally agree with your UI Suggestion but I'm just a developer and can't really change the design being approved by the stakeholders. – Daksh Gargas May 14 '19 at 09:52
  • Okay, let's say I'll use buttons as displayed in the picture, how will my `CollectionView` grow? I guess I'll be stuck with the same problem. I mean, the problem will stay the same. I can't really provide a fixed size for the button! – Daksh Gargas May 14 '19 at 09:55
  • @Dennis i'm not sure if its possible with stackviews, but I know collectionviews have extra functions to help with this. Heres an example third party control that looks like it does exactly this: https://github.com/zekunyan/TTGTagCollectionView – Simon McLoughlin May 14 '19 at 10:30