UIStackView flexible width and constant width items - ios

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

Related

stackview constraints break when adding two views inside with imageview having fixed width and height [duplicate]

This question already has answers here:
Strange UIView-Encapsulated-Layout-Height Error
(11 answers)
Closed 2 days ago.
i have a stackview with an imageview and a label underneath it but when i try to add it into stackview it doesnt appear and apparently all the constraints break.i want the imageview to be fixed width and height and the stackview to equal the width of the label
let userView_stackView = UIStackView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
userView_stackView.axis = .vertical
userView_stackView.alignment = .center
userView_stackView.spacing = 5
userView_stackView.addArrangedSubview(user_imageView)
userView_stackView.addArrangedSubview(user_name)
self.contentView.addSubview(userView_stackView)
stackView_constraints()
}
var user_imageView: UIImageView = {
let imageView = UIImageView()
let imageViewHeightAndWidth: CGFloat = 60
let image = UIImage(named: "steve")
imageView.image = image
imageView.layer.borderWidth = 1
imageView.clipsToBounds = true
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.cornerRadius = imageViewHeightAndWidth / 2
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.heightAnchor.constraint(equalToConstant: imageViewHeightAndWidth).isActive = true
imageView.widthAnchor.constraint(equalToConstant: imageViewHeightAndWidth).isActive = true
return imageView
}()
var user_name: UILabel = {
let label = UILabel()
label.text = "Steve Rodriquez"
label.font = label.font.withSize(14)
return label
}()
func stackView_constraints() {
userView_stackView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 0).isActive =
true
userView_stackView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 0)
.isActive = true
userView_stackView.trailingAnchor.constraint(
equalTo: self.contentView.trailingAnchor, constant: 0
).isActive = true
userView_stackView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: 0)
.isActive = true
}
Adding views like this breaks the constraints and prints the following error on the console where all the constraints are breaking
[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:0x280d70eb0 UIStackView:0x10327c250.height == 283 (active)>",
"<NSLayoutConstraint:0x280d72580 'UIView-Encapsulated-Layout-Height' UIStackView:0x10327c250.height == 0 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x280d70eb0 UIStackView:0x10327c250.height == 283 (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.
2019-10-12 10:43:30.597559-0500 Fourmi[1708:291157] [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:0x280d5f610 UIImageView:0x10327c6d0.width == 60 (active)>",
"<NSLayoutConstraint:0x280d72c10 'UISV-canvas-connection' UIStackView:0x10327c250.leading == _UILayoutSpacer:0x281174960'UISV-alignment-spanner'.leading (active)>",
"<NSLayoutConstraint:0x280d73020 'UISV-canvas-connection' UIStackView:0x10327c250.centerX == UIImageView:0x10327c6d0.centerX (active)>",
"<NSLayoutConstraint:0x280d72d50 'UISV-spanning-boundary' _UILayoutSpacer:0x281174960'UISV-alignment-spanner'.leading <= UIImageView:0x10327c6d0.leading (active)>",
"<NSLayoutConstraint:0x280d72300 'UIView-Encapsulated-Layout-Width' UIStackView:0x10327c250.width == 0 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x280d5f610 UIImageView:0x10327c6d0.width == 60 (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.
2019-10-12 10:43:30.598068-0500 Fourmi[1708:291157] [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:0x280d5f5c0 UIImageView:0x10327c6d0.height == 60 (active)>",
"<NSLayoutConstraint:0x280d72b70 'UISV-canvas-connection' UIStackView:0x10327c250.top == UIImageView:0x10327c6d0.top (active)>",
"<NSLayoutConstraint:0x280d72bc0 'UISV-canvas-connection' V:[UILabel:0x10327e990'Steve Rodriquez']-(0)-| (active, names: '|':UIStackView:0x10327c250 )>",
"<NSLayoutConstraint:0x280d72c60 'UISV-spacing' V:[UIImageView:0x10327c6d0]-(5)-[UILabel:0x10327e990'Steve Rodriquez'] (active)>",
"<NSLayoutConstraint:0x280d72580 'UIView-Encapsulated-Layout-Height' UIStackView:0x10327c250.height == 0 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x280d5f5c0 UIImageView:0x10327c6d0.height == 60 (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.
2019-10-12 10:43:30.598469-0500 Fourmi[1708:291157] [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:0x280d72b70 'UISV-canvas-connection' UIStackView:0x10327c250.top == UIImageView:0x10327c6d0.top (active)>",
"<NSLayoutConstraint:0x280d72bc0 'UISV-canvas-connection' V:[UILabel:0x10327e990'Steve Rodriquez']-(0)-| (active, names: '|':UIStackView:0x10327c250 )>",
"<NSLayoutConstraint:0x280d72c60 'UISV-spacing' V:[UIImageView:0x10327c6d0]-(5)-[UILabel:0x10327e990'Steve Rodriquez'] (active)>",
"<NSLayoutConstraint:0x280d72580 'UIView-Encapsulated-Layout-Height' UIStackView:0x10327c250.height == 0 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x280d72c60 'UISV-spacing' V:[UIImageView:0x10327c6d0]-(5)-[UILabel:0x10327e990'Steve Rodriquez'] (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.
2019-10-12 10:43:30.598894-0500 Fourmi[1708:291157] [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.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSAutoresizingMaskLayoutConstraint:0x280d40000 h=--& v=--& UIStackView:0x10327c250.width == 0 (active)>",
"<NSLayoutConstraint:0x280d5ff20 UIStackView:0x10327c250.width == UITableViewCellContentView:0x10327fdb0.width (active)>",
"<NSLayoutConstraint:0x280d40370 'fittingSizeHTarget' UITableViewCellContentView:0x10327fdb0.width == 375 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x280d5ff20 UIStackView:0x10327c250.width == UITableViewCellContentView:0x10327fdb0.width (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.
2019-10-12 10:43:30.599762-0500 Fourmi[1708:291157] [Warning] Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a table view cell's content view. We're considering the collapse unintentional and using standard height instead. Cell: <Fourmi.ChatTableViewCell: 0x10327af70; baseClass = UITableViewCell; frame = (0 0; 375 44); autoresize = W; layer = <CALayer: 0x282e41300>>
adding userView_stackView.translatesAutoresizingMaskIntoConstraints=falsefixed it

Scrollview working by breaking constraint

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

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):

Resources