Dynamic Height UITableView

Ali Akhtar
7 min readDec 17, 2022
https://developer.apple.com/documentation/uikit/uitableview

Prerequisite

You are pro developer using UITableView and AutoLayout. Also this blog is written to document thing what I learned so ignore some spelling mistake and other stuff if you understand it will be good and if something confusing comment

UITableView

A view that presents data using rows in a single column. Table views in iOS display rows of vertically scrolling content in a single column. Each row in the table contains one piece of your app’s content. For example, the Contacts app displays the name of each contact in a separate row, and the main page of the Settings app displays the available groups of settings. You can configure a table to display a single long list of rows, or you can group related rows into sections to make navigating the content easier.

Getting Started

As shown in Gist and Figure 1, we created simple tableView with fixed height 300

Gist 1
Figure 1

As shown in Gif 1 , this device has lots of space but we fixed the height of UITableView scrolling started and we are not using the space wisely. What I want is to dynamically increase the height of UITableView According to its children size,

Gif 1

As shown in Gif2 now height of UITableView dynamically increases , according to child contents, By doing few things. Lets talk about few things

  • contentSize → contentSize defines how big the scrollable content is. It is the size of the content within the UIScrollView and how long it can be within the UIScrollView. The scroll view must know the size of the content-view so it knows when to stop scrolling. its default value is zero, and it must be set to use any scroll view, even if the content-size is smaller than the scroll view’s own size. When TableView rendered it’s whole content it set this value A/C to total size of the content. It includes UI that not displaying at all in the screen → total size of content automatically created appearing or not appearing in scree
  • noIntrinsicMetric → The absence of an intrinsic metric for a given numeric view property. In short it rely on auto layout algorihtm size calculation
  • intrinsicContentSize → Custom views typically have content that they display of which the layout system is unaware. Setting this property allows a custom view to communicate to the layout system what size it would like to be based on its content. This intrinsic size must be independent of the content frame, because there’s no way to dynamically communicate a changed width to the layout system based on a changed height, for example. If a custom view has no intrinsic size for a given dimension, it can use noIntrinsicMetric for that dimension.
  • invalidateIntrinsicContentSize → Invalidates the view’s intrinsic content size .Call this when something changes in your custom view that invalidates its intrinsic content size. This allows the constraint-based layout system to take the new intrinsic content size into account in its next layout pass.

Explanation:

In Figure 2 and 3 what is happening ,

  • First we remove the height constraint of UITableView, which will lead to autolayout ambigious height error since UITableView
  • Once tableview contentSize (which is autucal size whole content we have) we called invalidateIntrinsicContentSize which basically called intrinsicContentSize . Rember contentSize is the size of content in tableview whereas intrinsicContentSize is the tableView height where you see content so if intrinsicContentSize < contentSize it means it can scroll since content view is more than the one who is showing content which is tableview
  • In short what we did we tell tableview use autolayout for everything except for height, height I will provide and when I will provide once my whole contentSize is rendered and it automatically know its content height, so my height of tableview is same as it’s content
Figure 2
Figure 3
Gif 2

As shown in Figure Figure 4 , here return CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric) which means use autolayout only, but we remove the height constraint previously that’s why for autolauout height is ambigious

Figure 4

Problem1 : As you can see in Gif 2 if the intrinsic content size of tableview (which is it’s height) is equal to content size.height . but why tableView is still scrolling and the answer is as shown in Figure 5, adjustedContentInset value is 34 which means in simple word we are telling our content view to start from 34 which means our tableview actual contentSize height is 589.33333333333326 , and the tableview height (intrinsic size) is 589.33333333333326 (since contentSize height == tableview height when we do invalidateIntrinsicContentSize). But the scrollabale area of tablview is (589.33333333333326 + 34) which is contentSize height + adjustedContentInset, that’s why it is scrolling and you see scrollable bar also showing

adjustedContentInset → The insets derived from the content insets and the safe area of the scroll view. Use this property to obtain the adjusted area in which to draw content. The contentInsetAdjustmentBehavior property determines whether the safe area insets are included in the adjustment. The safe area insets are then added to the values in the contentInset property to obtain the final value of this property.

Figure 5

The solution to this problem is we set the tbl.contentInsetAdjustmentBehavior = .never which Do not adjust the scroll view insets.

contentInsetAdjustmentBehavior → The behavior for determining the adjusted content offsets. This property specifies how the safe area insets are used to modify the content area of the scroll view. The default value of this property is UIScrollView.ContentInsetAdjustmentBehavior.automatic.

Figure 6
Gif 3

Problem2 :

Now see no content offset is added by tableview and there is no scroll bar at the right which means out content height is now perfectly same as height of tableview, but still you see it can scroll and the truth is it is not scrolling only scroll view bounces past the edge of content and back again

bounces → A Boolean value that controls whether the scroll view bounces past the edge of content and back again.If the value of this property is true, the scroll view bounces when it encounters a boundary of the content. Bouncing visually indicates that scrolling has reached an edge of the content. If the value is false, scrolling stops immediately at the content boundary without bouncing. The default value is true.

As shown in Figure 7, we set bounces to false, now our tableview appear as a view no scrolling or anything and grows dynamically, people will ask why not stackview for these type of case yes we can use stackview but I will show one use case where we need this type of thing but tableview

Figure 7

Now think about this case where content is too large that it actually can’t come on this screen , if we implement this with stackView we need to add lots of logic to make it scrollable by manually doing height calculation and embedded stackView in scrollView, but with tableView we can implement some simple logic to achieve this thing, like to enable scrolling when you reach some height limit,

Figure 8

As shown in Figure 9 , we specify max height threshold of our tableview and say if height is less than (screen height — 100) don’t enable scrolling and make the height of tableview same as its content which will not make tablview scrollable , but if it is greater than this then allow tableview to scroll and also make its height (screen height — 100) which is obviously less than its content size which auto do scrolling of isScrollEnabled is true

isScrollEnabled → A Boolean value that determines whether scrolling is enabled.The default value is true, which indicates that scrolling is enabled. Setting the value to false disables scrolling.
When scrolling is disabled, the scroll view doesn’t accept touch events; it forwards them up the responder chain. Note intially in example we can use this thing as well but to understand contentInsetAdjustmentBehavior I didn’t do this

Figure 9

--

--