Scrollview working by breaking constraint - ios

I have a UIViewController containing a scrollView: the scrollView is pinned (0,0,0,0) to the superview.
The scrollView contains a Content View with the following constraints set:
Inside this view, I put a square image view: it is pinned this way and its height equals the width of its superview.
Anything I described until now is done manually in the storyboard.
Then, using a simple button (so, after viewDidLoad, viewDidLayoutSubviews, etc.), I execute the following function (that 375 is currently hard-coded, but it is the heigth of the image view frame on the device I’m using for testing purposes):
var startH = 0
for i in 0...10 {
let v = UIView(frame: CGRect(x: 0, y: 375+startH, width: 375, height: startH))
v.backgroundColor = .random
contentView.addSubview(v)
startH += 100
}
let scrollerLayoutGuide = scrollView.contentLayoutGuide
scrollerLayoutGuide.heightAnchor.constraint(equalToConstant: CGFloat(startH+375)).isActive = true
scrollView.contentSize = contentView.frame.size
This should (and actually it does) create 11 views under the imageView, inside the contentView of the scrollView.
Problem is when I execute this function I get the following error:
[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:0x6000019d7d40 UIView:0x7fe66940aa30.height == UIScrollView:0x7fe66985b400.height (active)>",
"<NSLayoutConstraint:0x6000019d7d90 V:|-(0)-[UIView:0x7fe66940aa30] (active, names: '|':UIScrollView:0x7fe66985b400 )>",
"<NSLayoutConstraint:0x6000019d7de0 V:[UIView:0x7fe66940aa30]-(0)-| (active, names: '|':UIScrollView:0x7fe66985b400 )>",
"<NSLayoutConstraint:0x6000019e4690 UILayoutGuide:0x6000003c81c0'UIViewSafeAreaLayoutGuide'.bottom == UIScrollView:0x7fe66985b400.bottom (active)>",
"<NSLayoutConstraint:0x6000019e4730 UIScrollView:0x7fe66985b400.top == UILayoutGuide:0x6000003c81c0'UIViewSafeAreaLayoutGuide'.top (active)>",
"<NSLayoutConstraint:0x6000019e11d0 _UIScrollViewLayoutGuide:0x6000003ac1c0'UIScrollView-contentLayoutGuide'.height
== 1475 (active)>",
"<NSLayoutConstraint:0x6000019e9540 'UIView-Encapsulated-Layout-Height' UIView:0x7fe66950bdb0.height == 667 (active)>",
"<NSLayoutConstraint:0x6000019e45f0 'UIViewSafeAreaLayoutGuide-bottom' V:[UILayoutGuide:0x6000003c81c0'UIViewSafeAreaLayoutGuide']-(0)-| (active, names: '|':UIView:0x7fe66950bdb0 )>",
"<NSLayoutConstraint:0x6000019e4550 'UIViewSafeAreaLayoutGuide-top' V:|-(20)-[UILayoutGuide:0x6000003c81c0'UIViewSafeAreaLayoutGuide'] (active, names: '|':UIView:0x7fe66950bdb0 )>" )
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x6000019d7de0 V:[UIView:0x7fe66940aa30]-(0)-| (active, names: '|':UIScrollView:0x7fe66985b400 )>
Problem is I can't understand what constraint is causing this issue and, most of all, why. Could you help me?

There is conflict between your constraints with contentView
1. There is Top, bottom, leading, trailing with the scrollview
2. Fixed height and fixed width constraint of contentView
These two will conflict each other as OS will not be sure which constraint to fulfil.
As a solution reduce the priority of height and width constraint so that the more priority is given to the constraint with respect to the scrollView.
For more details please follow below tutorial
How to configure a UIScrollView with Auto Layout

Related

UIStackView flexible width and constant width items

TL;DR
I want to replace a custom (different from other items) width item in UIStackView with flexible width item and center all UIStackView items.
More info:
I have a UIStackView that holds few custom UIView's:
self.handleButtonStack.axis = .horizontal
self.handleButtonStack.alignment = .center
self.handleButtonStack.distribution = .fillProportionally
self.handleButtonStack.spacing = 10.0
let hbVideo = HandleButton(image: "icon", title: "", type: .video, delegate: self)
hbVideo.widthAnchor.constraint(equalToConstant: 50).isActive = true
let hbInstagram = HandleButton(image: "icon", title: "", type: .instagram, delegate: self)
hbInstagram.widthAnchor.constraint(equalToConstant: 50).isActive = true
let hbWhatsApp = HandleButton(image: "icon", title: "", type: .whatsapp, delegate: self)
hbWhatsApp.widthAnchor.constraint(equalToConstant: 50).isActive = true
let hbHints = HandleButton(image: "icon", title: "title", type: .hint, delegate: self)
hbHints.widthAnchor.constraint(greaterThanOrEqualToConstant: 100).isActive = true
self.handleButtonStack.addArrangedSubview(hbVideo)
self.handleButtonStack.addArrangedSubview(hbInstagram)
self.handleButtonStack.addArrangedSubview(hbWhatsApp)
self.handleButtonStack.addArrangedSubview(hbHints)
After the user has preformed some action I want to change the UIStackView and remove the hbHints button and center the items.
I do that in this way:
if let subviews = self.handleButtonStack.arrangedSubviews as? [HandleButton] {
if let hintsButton = subviews.last {
self.handleButtonStack.removeFully(view: hintsButton)
let leadingSpacer = self.createSpacer(width: 50)
let trailingSpacer = self.createSpacer(width: 50)
self.handleButtonStack.insertArrangedSubview(leadingSpacer, at: 0)
self.handleButtonStack.insertArrangedSubview(trailingSpacer, at: subviews.count)
}
}
And adding a spacer like that:
func createSpacer(width: CGFloat) -> UIView {
let space = UIView(frame: .zero)
space.backgroundColor = .red
space.translatesAutoresizingMaskIntoConstraints = false
if width != 0 {
space.widthAnchor.constraint(equalToConstant: width).isActive = true
}
return space
}
My problem is that the Constraints are breaking with error and I can't figure out why. Is it possible to add a flexible width as spacer that stretch as I put it in place?
What I already tried:
Set a contentHuggingPriority to the items
Set a contentCompressionResistancePriority to the items
Adding constraints to the spacer item
Removing the width constraint for the spacer item
No success.
Here is the constraints breaking log:
[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:0x283414050 H:[UIStackView:0x124599e30]-(0)-| (active, names: '|':UIView:0x1245e9f20 )>",
"<NSLayoutConstraint:0x2834142d0 H:|-(0)-[UIStackView:0x124599e30] (active, names: '|':UIView:0x1245e9f20 )>",
"<NSLayoutConstraint:0x283416e90 UILayoutGuide:0x282e94460'UIViewSafeAreaLayoutGuide'.trailing == UIView:0x1245e9f20.trailing + 40 (active)>",
"<NSLayoutConstraint:0x283416620 UIView:0x1245e9f20.leading == UILayoutGuide:0x282e94460'UIViewSafeAreaLayoutGuide'.leading + 40 (active)>",
"<NSLayoutConstraint:0x283428b90 MyApp.HandleButton:0x124589460.width == 50 (active)>",
"<NSLayoutConstraint:0x283428af0 MyApp.HandleButton:0x124589e40.width == 50 (active)>",
"<NSLayoutConstraint:0x283428a50 MyApp.HandleButton:0x124589610.width == 50 (active)>",
"<NSLayoutConstraint:0x2834281e0 'UISV-canvas-connection' UIStackView:0x124599e30.leading == UIView:0x124576f20.leading (active)>",
"<NSLayoutConstraint:0x283428230 'UISV-canvas-connection' H:[UIView:0x1245897c0]-(0)-| (active, names: '|':UIStackView:0x124599e30 )>",
"<NSLayoutConstraint:0x2834282d0 'UISV-fill-proportionally' UIView:0x124576f20.width == 0 (active)>",
"<NSLayoutConstraint:0x28342bc50 'UISV-fill-proportionally' UIView:0x1245897c0.width == 0 (active)>",
"<NSLayoutConstraint:0x283428280 'UISV-spacing' H:[UIView:0x124576f20]-(10)-[MyApp.HandleButton:0x124589460] (active)>",
"<NSLayoutConstraint:0x28342acb0 'UISV-spacing' H:[MyApp.HandleButton:0x124589460]-(10)-[MyApp.HandleButton:0x124589e40] (active)>",
"<NSLayoutConstraint:0x28342af80 'UISV-spacing' H:[MyApp.HandleButton:0x124589e40]-(10)-[MyApp.HandleButton:0x124589610] (active)>",
"<NSLayoutConstraint:0x28342b2a0 'UISV-spacing' H:[MyApp.HandleButton:0x124589610]-(10)-[UIView:0x1245897c0] (active)>",
"<NSLayoutConstraint:0x283429810 'UIView-Encapsulated-Layout-Width' MyApp.AngleColorsView:0x124599fc0.width == 414 (active)>",
"<NSLayoutConstraint:0x283415f90 'UIViewSafeAreaLayoutGuide-left' H:|-(0)-[UILayoutGuide:0x282e94460'UIViewSafeAreaLayoutGuide'](LTR) (active, names: '|':MyApp.AngleColorsView:0x124599fc0 )>",
"<NSLayoutConstraint:0x283416440 'UIViewSafeAreaLayoutGuide-right' H:[UILayoutGuide:0x282e94460'UIViewSafeAreaLayoutGuide']-(0)-|(LTR) (active, names: '|':MyApp.AngleColorsView:0x124599fc0 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x283428a50 MyApp.HandleButton:0x124589610.width == 50 (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
Here you need not give any centre alignment. As per your requirement you don't need that I think as you are giving constraints for all of your views and for the last view you are also giving greaterThanOrEqual constraint which automatically stretches your view to fill up the gaps.
So try changing the alignment from .center to .fill.
Then after you delete your last view you don't have to add any empty spacer to fill up the missing fields. Instead you can give constraints for your stack view itself.
For the leading and trailing anchor of the stack view give greaterThanOrEqualTo constraint instead of equal and also add a centre aligned constraint to the stack view.
So when you remove the view now the stack view automatically arranges the view for you in your needed centre aligned position.
Hope this is your expected end result.
expected output in GIF

Swift tableview cell proportional height

So I have a nice chart that I am adding into a tableview cell. I am trying to get this cell to always be 1/2 as tall as the width of the cell. I currently have the following constraints setup:
let cell = tableView.dequeueReusableCell(withIdentifier: "weatherCell", for: indexPath)
weatherGraph.translatesAutoresizingMaskIntoConstraints = false
cell.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(weatherGraph)
weatherGraph.leftAnchor.constraint(equalTo: cell.contentView.leftAnchor).isActive = true
weatherGraph.rightAnchor.constraint(equalTo: cell.contentView.rightAnchor).isActive = true
weatherGraph.topAnchor.constraint(equalTo: cell.contentView.topAnchor).isActive = true
weatherGraph.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor).isActive = true
cell.contentView.heightAnchor.constraint(equalTo: cell.contentView.widthAnchor, multiplier: 0.5).isActive = true
cell.selectionStyle = .none
This way I can support resizing of the cell when the orientation of the device changes. With what I have, I am getting the following layout errors:
[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:0x60000134a210 UITableViewCellContentView:0x7fcd28866c90.height == 0.5*UITableViewCellContentView:0x7fcd28866c90.width (active)>",
"<NSLayoutConstraint:0x60000134b890 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fcd28866c90.height == 187.667 (active)>",
"<NSLayoutConstraint:0x60000134bd40 'UIView-Encapsulated-Layout-Width' UITableViewCellContentView:0x7fcd28866c90.width == 375 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000134b890 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fcd28866c90.height == 187.667 (active)>
In my heightForRowAt I am returning UITableView.automaticDimension for this specific cell.
Adding the debug message for setting the height constraint on the weatherGraph:
[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:0x600000bee030 H:|-(0)-[Digital_Heat_Sheets_Dev_2.HeatWeatherGraph:0x7fb5e0747a30](LTR) (active, names: '|':UITableViewCellContentView:0x7fb5e072cc90 )>",
"<NSLayoutConstraint:0x600000bec910 Digital_Heat_Sheets_Dev_2.HeatWeatherGraph:0x7fb5e0747a30.right == UITableViewCellContentView:0x7fb5e072cc90.right (active)>",
"<NSLayoutConstraint:0x600000bec960 V:|-(0)-[Digital_Heat_Sheets_Dev_2.HeatWeatherGraph:0x7fb5e0747a30] (active, names: '|':UITableViewCellContentView:0x7fb5e072cc90 )>",
"<NSLayoutConstraint:0x600000beca00 Digital_Heat_Sheets_Dev_2.HeatWeatherGraph:0x7fb5e0747a30.bottom == UITableViewCellContentView:0x7fb5e072cc90.bottom (active)>",
"<NSLayoutConstraint:0x600000beca50 Digital_Heat_Sheets_Dev_2.HeatWeatherGraph:0x7fb5e0747a30.height == 0.5*Digital_Heat_Sheets_Dev_2.HeatWeatherGraph:0x7fb5e0747a30.width (active)>",
"<NSLayoutConstraint:0x600000bee120 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fb5e072cc90.height == 187.667 (active)>",
"<NSLayoutConstraint:0x600000bedfe0 'UIView-Encapsulated-Layout-Width' UITableViewCellContentView:0x7fb5e072cc90.width == 375 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600000beca50 Digital_Heat_Sheets_Dev_2.HeatWeatherGraph:0x7fb5e0747a30.height == 0.5*Digital_Heat_Sheets_Dev_2.HeatWeatherGraph:0x7fb5e0747a30.width (active)>
I can't figure out where the height is being set to 187.667 and why it is overriding my ratio constraint.
Have you tried setting this width-height ratio on the weather graph view itself?:
weatherGraph.heightAnchor.constraint(equalTo: weatherGraph.widthAnchor, multiplier: 0.5).isActive = true
Normally you shouldn't set any width/height constraints on the cell.contentView (or the cell itself) directly, since it's internally managed by UITableView, thus the constraints conflict.

How to add nibs to a UIStackView programmatically

I'm trying to add an arbitrary amount of view from nibs into a UIStackView. The issue is that, say, if only include one view, that view grows to fill the entire stackview, instead of maintaining the proper width. Here's my code so far:
friendStackView.autoresizingMask = .flexibleWidth
friendStackView.translatesAutoresizingMaskIntoConstraints = false
let friendView = Bundle.main.loadNibNamed("FriendView", owner: self, options: nil)?.first as! FriendViewController
friendStackView.addArrangedSubview(friendView)
friendView.heightAnchor.constraint(equalToConstant: 150).isActive = true
friendView.widthAnchor.constraint(equalToConstant: 120).isActive = true
It results in the following debug:
[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:0x14eb9eb0 UIStackView:0x14ee6ed0.width == 500 (active)>",
"<NSLayoutConstraint:0x14ef83f0 XXX.FriendViewController:0x14ef2090.width == 120 (active)>",
"<NSLayoutConstraint:0x14def090 'UISV-canvas-connection' UIStackView:0x14ee6ed0.leading == XXX.FriendViewController:0x14ef2090.leading (active)>",
"<NSLayoutConstraint:0x14def230 'UISV-canvas-connection' H:[XXX.FriendViewController:0x14ef2090]-(0)-| (active, names: '|':UIStackView:0x14ee6ed0 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x14ef83f0 XXX.FriendViewController:0x14ef2090.width == 120 (active)>
You have a conflict here the stackView width = 500 and you're trying to give the subview which is supposed to fill the whole width 120
"<NSLayoutConstraint:0x14eb9eb0 UIStackView:0x14ee6ed0.width == 500 (active)>",
"<NSLayoutConstraint:0x14ef83f0 XXX.FriendViewController:0x14ef2090.width == 120

Unable to simultaneously satisfy constraints when update height constraints of imageView swift 4

I have a stack view that look like the figure below:
So I change the height of the image programmatically to make it fit the image that download from my server,if dont have image,the height constraints of image will set to be zero.
Here is my code to doing so:
let imageUrl = URL(string :imageString)
if let data = try? Data(contentsOf: imageUrl!)
{
guard let actualImage: UIImage = UIImage(data: data) else{
print("No image!")
ImageView.image = nil
defaultImageHeightContrainst = ImageHeightContrainst.constant
ImageHeightContrainst.constant = 0
layoutIfNeeded()
return
}
let imageHeight = actualImage.size.height * actualImage.scale
print("imageHeight = \(imageHeight)")
defaultImageHeightContrainst = ImageHeightContrainst.constant
ImageHeightContrainst.constant = imageHeight
layoutIfNeeded()
//here display the image to the imageview
ImageView.kf.setImage(with: imageUrl)
}
With the code above,the image height is scale according to actual image height which download from internet.If dont have image,the "image" part also set to 0 already.
This is what I expected,but now I face an error below whenever the "image" height become taller in order to fit the actual image height
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:0x6080002868b0 UIImageView:0x7f9cbae59240.height == 50 (active)>",
"<NSLayoutConstraint:0x608000286bd0 UIView:0x7f9cbae5ad80.height == 1 (active)>",
"<NSLayoutConstraint:0x608000286d10 UIImageView:0x7f9cbae5b440.height == 458 (active)>",
"<NSLayoutConstraint:0x608000286f90 UIView:0x7f9cbae5bb50.height == 1 (active)>",
"<NSLayoutConstraint:0x6080002871c0 V:|-(0)-[UILabel:0x7f9cbae5b160] (active, names: '|':UIStackView:0x7f9cbae5af60 )>",
"<NSLayoutConstraint:0x608000287350 V:[UILabel:0x7f9cbae5b160]-(10)-[UIImageView:0x7f9cbae5b440] (active)>",
"<NSLayoutConstraint:0x6080002873a0 V:[UIImageView:0x7f9cbae5b440]-(10)-[UIStackView:0x7f9cbae5b670] (active)>",
"<NSLayoutConstraint:0x608000287580 V:[UIStackView:0x7f9cbae5b670]-(10)-[UIView:0x7f9cbae5bb50] (active)>",
"<NSLayoutConstraint:0x6080002875d0 V:[UIStackView:0x7f9cbae5c0f0]-(0)-| (active, names: '|':UIStackView:0x7f9cbae5af60 )>",
"<NSLayoutConstraint:0x608000287670 V:[UIView:0x7f9cbae5bb50]-(10)-[UIStackView:0x7f9cbae5c0f0] (active)>",
"<NSLayoutConstraint:0x6080002877b0 V:|-(10)-[UIImageView:0x7f9cbae59240] (active, names: '|':UITableViewCellContentView:0x7f9cbae5a0c0 )>",
"<NSLayoutConstraint:0x6080002878f0 V:[UIImageView:0x7f9cbae59240]-(8)-[UIView:0x7f9cbae5ad80] (active)>",
"<NSLayoutConstraint:0x6080002879e0 V:[UIStackView:0x7f9cbae5af60]-(10)-| (active, names: '|':UITableViewCellContentView:0x7f9cbae5a0c0 )>",
"<NSLayoutConstraint:0x608000287a80 V:[UIView:0x7f9cbae5ad80]-(8)-[UIStackView:0x7f9cbae5af60] (active)>",
"<NSLayoutConstraint:0x608000288c00 'UISV-canvas-connection' UIStackView:0x7f9cbae5c0f0.top == _UILayoutSpacer:0x6080001cd5c0'UISV-alignment-spanner'.top (active)>",
"<NSLayoutConstraint:0x608000288ca0 'UISV-canvas-connection' V:[_UILayoutSpacer:0x6080001cd5c0'UISV-alignment-spanner']-(0)-| (active, names: '|':UIStackView:0x7f9cbae5c0f0 )>",
"<NSLayoutConstraint:0x608000289970 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7f9cbae5a0c0.height == 476.5 (active)>"
)
Before asking,I already checked all my other constraints,which is all set correctly.I even disable all the code that can change the height of "image",once disable,there is no problem.The error only occurred when I intend to change the height.
I even tried to add ImageView.translatesAutoresizingMaskIntoConstraints = false before layoutIfNeeded(),but the error is still exist.
So what is the correct way to change the height of image in order to fit the actual image download from server?
Considering that the last constraint says
"<NSLayoutConstraint:0x608000289970 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7f9cbae5a0c0.height == 476.5 (active)>"
I assume you are using stackView inside of a UITableViewCell to implement automatic height cells in a tableView. If my assumption is correct, then the problem is not with the stackView, nor with the imageView, but with the way UITableView works with UITableViewAutomaticDimension and Autolayout. If the layout works as you expect, and the warning is the only thing that bugs you, then read following.
Therefore it seems to me that this is a result of an known "bug" - there is a collision of the height set by the tableView and the height calculated by the autolayout. When rendering the cell, the tableView first applies the default height, calculates the autolayout height, and then use the latter - at least it seems so. See my question. The constraint mentioned above ('UIView-Encapsulated-Layout-Height') is the one applied by the UITableView that later goes away.
That means that the constraints you are using are probably OK. Just set one of the constraints defining height to priority = 999 (so that until it deactivates the default height constraint it won't cause any conflict). In the end, it will result in using your constraint anyway, so it will not cause any layout trouble.
E.g., if you constrain the stackView to fit the cell's contentView, set the stackView.bottomAnchor to contentView.bottomAnchor just with the priority set to 999. If you did the layout programmatically, this might be your solution:
let bottomConstraint = tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
bottomConstraint.priority = UILayoutPriority(rawValue: 999)
NSLayoutConstraint.activate([
// rest of the constraints
stackView.topAnchor.constraint(equalTo: contentView.topAnchor),
stackView.leftAnchor.constraint(equalTo: contentView.leftAnchor),
stackView.rightAnchor.constraint(equalTo: contentView.rightAnchor),
bottomConstraint,
])
If you do the layout in storyboards, just select appropriate constraint in the storyboards, and in the attributes inspector set its priority to 999 (for example):

How to add UITextField programmatically to UIScrollView without breaking constraints?

The case goes like this: I have a form embed in a UIScrollView, in the form there's a part where the user can add N numbers of textField, so if at first I had this:
UITextField - textField1
UIButton - Add
When Add is pressed I want to have this:
UITextField - textField1
UITextField - textField2
UIButton - Add
And although the text field is added, the constraints cannot be satisfied and therefore the UI breaks
The log for that:
[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.
(
"<_UILayoutSupportConstraint:0x1c4c800a0 _UILayoutGuide:0x106ccf4e0.height == 64 (active)>",
"<_UILayoutSupportConstraint:0x1c4c80050 V:|-(0)-[_UILayoutGuide:0x106ccf4e0] (active, names: '|':UIView:0x106ccdc10 )>",
"<_UILayoutSupportConstraint:0x1c4c80ff0 _UILayoutGuide:0x106ccf6d0.height == 0 (active)>",
"<_UILayoutSupportConstraint:0x1c4c801e0 _UILayoutGuide:0x106ccf6d0.bottom == UIView:0x106ccdc10.bottom (active)>",
"<NSLayoutConstraint:0x1c4c80550 UIImageView:0x106cce6c0.height == 5 (active)>",
"<NSLayoutConstraint:0x1c4c80640 UILabel:0x106ccf070'Completa tu Perfil'.height == 24 (active)>",
"<NSLayoutConstraint:0x1c0c886b0 form-view.height == 579 (active, names: form-view:0x10ed307c0 )>",
"<NSLayoutConstraint:0x1c0c8a1e0 V:|-(0)-[form-view] (active, names: form-view:0x10ed307c0, '|':UIScrollView:0x107a37000 )>",
"<NSLayoutConstraint:0x1c0c8a320 V:[form-view]-(0)-[profiles-view] (active, names: profiles-view:0x106ccd430, form-view:0x10ed307c0 )>",
"<NSLayoutConstraint:0x1c4c80af0 V:[_UILayoutGuide:0x106ccf4e0]-(10)-[UILabel:0x106ccf070'Completa tu Perfil'] (active)>",
"<NSLayoutConstraint:0x1c4c80cd0 V:[UILabel:0x106ccf070'Completa tu Perfil']-(8)-[UIImageView:0x106cce6c0] (active)>",
"<NSLayoutConstraint:0x1c4c80d20 V:[UIImageView:0x106cce6c0]-(0)-[UIScrollView:0x107a37000] (active)>",
"<NSLayoutConstraint:0x1c4c80e10 UIImageView:0x106ccddf0.top == profiles-view.top (active, names: profiles-view:0x106ccd430 )>",
"<NSLayoutConstraint:0x1c4c80f00 V:[UIImageView:0x106ccddf0]-(0)-[_UILayoutGuide:0x106ccf6d0] (active)>",
"<NSLayoutConstraint:0x1c0c8bdb0 'UIView-Encapsulated-Layout-Height' UIView:0x106ccdc10.height == 667 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x1c0c886b0 form-view.height == 579 (active, names: form-view:0x10ed307c0 )>
So, since the height constraint was broken, AutoLayout arrange the elements following the margin constraints which allows the views broke that way.
That being said, the way I am adding the constraints is this:
func addModelButtonAction(_ sender: Any) { // an IBAction
addButton.isHighlighted = false
let last = modelTextFields.last!
let textField = last.createCopy() // extension method for creating a copy of the last textField
modelTextFieldsView.insertSubview(textField, belowSubview: last)
let growth = last.frame.height + 8 // the 8 represents the top spacing between textFields
formViewHeight.constant += growth // increasing height of the view where the form is embeded
modelTextFieldsHeight.constant += growth // increasing height of the view where the textFields are embeded
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
textField.frame.origin.y += growth // moving new textField below the previous one
}
modelTextFields.append(textField) // array of UITextField to keep track of the textFields in screen
}
And the view's alignment rectangles:
And the view's hierarchy:
What can I do to make this work as expected? I appreciate your help in this, because I've been trying to figure this out without any success.
Thanks in advance!
You have a couple of options to solve this layout issue:
Personally, I might try embedding these views in a UIStackView. The stack view will work to manage the vertical layout for you, allowing you to insert and remove subviews as needed. UIStackView is especially easy to work with from Interface Builder if you use Storyboards.
Alternatively, you could use a UITableView for this layout; it would manage the vertical flow on your behalf, abstracting much of the layout headache from you, though you'd need to manage the data source and cells yourself.
You could probably get this layout to work without either of these by carefully managing the priority of different constraints, allowing some to be broken as the layout changes, but this can be a tedious chore.

Resources