Troubleshooting: iOS auto layout warning about UIView-Encapsulated-Layout-Height
Symptom
In a table view cell layout, there is no layout constraints issue in xcode. However during run time, xcode console report following layout constraints issue:
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x6000012c0190 UIView:0x7fdefe74a240.height == 1 (active)>",
"<NSLayoutConstraint:0x6000012c0960 MyModule.MyAwesomeControl:0x7fdefe721d90.height == 48 (active)>",
"<NSLayoutConstraint:0x6000012c40a0 V:|-(16)-[UIImageView:0x7fdefe747ae0] (active, names: '|':UITableViewCellContentView:0x7fdefe747940 )>",
"<NSLayoutConstraint:0x6000012c4410 V:[UIImageView:0x7fdefe747ae0]-(12)-[UIView:0x7fdefe74a240] (active)>",
"<NSLayoutConstraint:0x6000012c4690 V:[UIView:0x7fdefe74a240]-(20)-[UITextView:0x7fdefe8f3400'No network is currently d...'] (active)>",
"<NSLayoutConstraint:0x6000012c47d0 V:[MyModule.MyAwesomeControl:0x7fdefe721d90]-(50)-| (active, names: '|':UITableViewCellContentView:0x7fdefe747940 )>",
"<NSLayoutConstraint:0x6000012c4820 MyModule.MyAwesomeControl:0x7fdefe721d90.top == UITextView:0x7fdefe8f3400'Awesome text here...'.top + 56 (active)>",
"<NSLayoutConstraint:0x6000012b9040 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fdefe747940.height == 32 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x6000012c0960 MyModule.MyAwesomeControl:0x7fdefe721d90.height == 48 (active)>
The layout constraints include UIView-Encapsulated-Layout-Height
which not part of original view layout constraints.
However from the UI perspective, thought this warning exist, the layout looks correctly, it didn’t break the constraint mentioned above. It actually break 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fdefe747940.height == 32
. It is kind of weird.
Analyze
What is UIView-Encapsulated-Layout-Height
The UIView-Encapsulated-Layout-Height
constraint is added by UITableView
, the value 32
(or whatever number) should be cell height.
However in this case the actual cell height is not 32
. 32
is estimated row height.
Auto Height for TableView Cell
In iOS, you can use Auto Layout to define the height of a table view cell; however, the feature is not enabled by default.
Normally, a cell’s height is determined by the table view delegate’s tableView:heightForRowAtIndexPath:
method.
To enable self-sizing table view cells, you must set the table view’s rowHeight
property to UITableViewAutomaticDimension
.
You must also assign a value to the estimatedRowHeight
property.
As soon as both of these properties are set, the system uses Auto Layout to calculate the row’s actual height.
First make sure let UITableView
determine its cell height automatically with use following code:
tableView.estimatedRowHeight = 32; // or any number, but need set a number to make it work.
tableView.rowHeight = UITableView.automaticDimension
After this settings, the cell should calculate its height automatically.
Then lay out the table view cell’s content within the cell’s content view. To define the cell’s height, you need an unbroken chain of constraints and views (with defined heights) to fill the area between the content view’s top edge and its bottom edge. If your views have intrinsic content heights, the system uses those values. If not, you must add the appropriate height constraints, either to the views or to the content view itself.
Additionally, try to make the estimated row height as accurate as possible. The system calculates items such as the scroll bar heights based on these estimates. The more accurate the estimates, the more seamless the user experience becomes.
The Real Scenario
From the UI perspective, thought this warning exist, the layout looks correctly, it didn’t break the constraint mentioned above. It actually break 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fdefe747940.height == 32
. Looks like Xcode give wrong warning at the first place.
Root Cause
After code review I found a call to layoutIfNeeded()
after change some view attributes.
I suspect maybe this caused issue, the reason is when call layoutIfNeeded()
it lays out the subviews immediately. Since the cell height is not determined yet, so it use estimated height and caused warning.
After actual cell height is determined the cell will layout one more time with correct cell height. This explain why UI looks correct and not use estimated row height.
layoutIfNeeded()
Declaration
func layoutIfNeeded()
Discussion
Use this method to force the view to update its layout immediately. When using Auto Layout, the layout engine updates the position of views as needed to satisfy changes in constraints. Using the view that receives the message as the root view, this method lays out the view subtree starting at the root. If no layout updates are pending, this method exits without modifying the layout or calling any layout-related callbacks.
Solution
First make sure table view cell is set to auto height:
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 32;
Then the solution to remove this weird UIView-Encapsulated-Layout-Height
warning is simple:
find and remove un-necessary layoutIfNeeded()
.
Then Xcode will not report any layout constraints warnings and layout is correct.
Related pages:
- Swift Data init with heap buffer from C and free in Swift
- DispatchQueue QoS Order Explained Best Practices & Common Pitfalls to Avoid
- iOS RUNNINGBOARD 0xdead10cc crash troubleshooting
- iOS objc_retain crash troubleshooting
- Fastlane Best Practices for iOS and Troubleshooting Tips
- SwiftUI: How to Tap to Select All Text in a TextField on iOS
- Direct Download Link for All Xcode Releases/Beta, Compilers and SDK Information
- Guide: Jailbreaking Apple TV 4K
- iOS Security: App security in iOS and iPadOS - code signing, entitlement and sandbox etc.
- Tips on Use Swift Package Manager (SPM) with Continuous Integration / Delivery (CI/CD)
- Jailbreak iPhone 8 iOS 16.2 with palera1n and use frida dump to decrypt ipa
- Use frida and objection to penetration test iOS app security
- Troubleshooting: loading carthage framework error: dyld: Library not loaded: @rpath/...
- What's new in SwiftUI iOS 16.4 beta 2
References
OmniLock - Block / Hide App on iOS
Block distractive apps from appearing on the Home Screen and App Library, enhance your focus and reduce screen time.
DNS Firewall for iOS and Mac OS
Encrypted your DNS to protect your privacy and firewall to block phishing, malicious domains, block ads in all browsers and apps