Autolayout - why are these constrainsts unsatisfiable? - swift

So I have built my system of views and constraints, and sometimes I get unsatisfiable constraints error (resolved by breaking constraint). Can anyone tell me why are the following constraints unsatisfiable? (paste it to https://www.wtfautolayout.com/ to make it clearer).
(
"<NSLayoutConstraint:0x600000a94050 UILayoutGuide:0x6000010b47e0'colsep guide 1'.width == UILayoutGuide:0x6000010b4620'etalon'.width (active)>",
"<NSLayoutConstraint:0x600000a85c70 BASE keyboard.trailing == Keyboard frame.trailing (active, names: BASE keyboard:0x7fd018e0d9e0, Keyboard frame:0x7fd018e0d7c0 )>",
"<NSLayoutConstraint:0x600000a85e50 H:|-(0)-[SCIENCE keyboard] (active, names: SCIENCE keyboard:0x7fd018e1c340, Keyboard frame:0x7fd018e0d7c0, '|':Keyboard frame:0x7fd018e0d7c0 )>",
"<NSLayoutConstraint:0x600000a81540 H:|-(0)-[Keyboard frame] (active, names: Keyboard frame:0x7fd018e0d7c0, Main app frame:0x7fd018e06280, '|':Main app frame:0x7fd018e06280 )>",
"<NSLayoutConstraint:0x600000a81590 Keyboard frame.trailing == Main app frame.trailing (active, names: Keyboard frame:0x7fd018e0d7c0, Main app frame:0x7fd018e06280 )>",
"<NSLayoutConstraint:0x600000a85fe0 H:[SCIENCE keyboard]-(0)-[BASE keyboard] (active, names: BASE keyboard:0x7fd018e0d9e0, SCIENCE keyboard:0x7fd018e1c340 )>",
"<NSLayoutConstraint:0x600000a860d0 SCIENCE keyboard.width == 0.5*Keyboard frame.width (active, names: SCIENCE keyboard:0x7fd018e1c340, Keyboard frame:0x7fd018e0d7c0 )>",
"<NSLayoutConstraint:0x600000a94c80 'etalon width' UILayoutGuide:0x6000010b4620'etalon'.width == 0.03*BASE keyboard.width (active, names: BASE keyboard:0x7fd018e0d9e0 )>",
"<NSLayoutConstraint:0x600000a81b80 'nonex leading' Main app frame.leading == UILayoutGuide:0x6000010b78e0'UIViewSafeAreaLayoutGuide'.leading (active, names: Main app frame:0x7fd018e06280 )>",
"<NSLayoutConstraint:0x600000a81bd0 'nonex trailing' Main app frame.trailing == UILayoutGuide:0x6000010b78e0'UIViewSafeAreaLayoutGuide'.trailing (active, names: Main app frame:0x7fd018e06280 )>",
"<NSLayoutConstraint:0x600000af2080 'UIView-Encapsulated-Layout-Width' Whole window frame.width == 414 (active, names: Whole window frame:0x7fd018d04080 )>",
"<NSLayoutConstraint:0x600000a819f0 'UIViewSafeAreaLayoutGuide-left' H:|-(0)-[UILayoutGuide:0x6000010b78e0'UIViewSafeAreaLayoutGuide'](LTR) (active, names: Whole window frame:0x7fd018d04080, '|':Whole window frame:0x7fd018d04080 )>",
"<NSLayoutConstraint:0x600000a81a90 'UIViewSafeAreaLayoutGuide-right' H:[UILayoutGuide:0x6000010b78e0'UIViewSafeAreaLayoutGuide']-(0)-|(LTR) (active, names: Whole window frame:0x7fd018d04080, '|':Whole window frame:0x7fd018d04080 )>"
)
It may seem complicated, but it is not. Basic structure is [Whole window frame] - [UIViewSafeAreaLayoutGuide] - [Main app frame] - [Keyboard frame] ... each one inside the previous one, taking space from left to right, so all of them should have same width. Then inside [Main app frame] there is [SCIENCE keyboard] and [BASE keyboard] side by side, each taking half of available width. Inside [BASE keyboard] I have [etalon] with width as 0.03 multiple of parent width, and then [colsep guide 1] with the same width as etalon.
During runtime, swift insists that these constraints are unsatisfiable and resolves them by breaking the first one ([colsep guide 1].width = [etalon].width) . But why? The structure is quite simple, I can resolve it by hand just by propagating width of [Whole window frame] down. And breaking of the first constraint changes absolutely nothing.

Got it! It seems a bit like a bug in autolayout to me, but I found the reason of problems. Inside keyboard views I was making a grid of spacers (UILayoutGuides), between which the buttons of keyboard were pinned. Spacers' position was specified by constraint to parent trailing (or bottom for verticals) with multiplier. In order to put it at percentage of parent's width (or height).
Such constraint is not possible to create with anchor api (you can't do anything like g.centerXAnchor.constraint(equalTo: self.trailingAnchor, multiplier: 0.5)
). But it is possible to create with basic NSLayoutConstraint, it clearly works in interface builder, and is even recommended in some stackoverflow questions.
I found out that it possibly works, but under some circumstances, it breaks layout in a very weird way. After some activating and deactivating groups of constraints, these constraints started to break in a very weird way, sometimes even silently. So I added some UILayoutGuides taking width (or height) as a multiplier of parent, and then using their trailing (or top) edges to pin centers of my spacers to. Percentage of with or height is possible to do with anchors api, and does not break.
Damn, this was a really nasty one.

Related

Auto Layout error with tableview cell in swift

I'm using autolayout with UITableViewCell and got following errors.
How can I fix it?
2020-09-15 11:42:13.104796+0900 heart-to-heart[14602:1800620] [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:0x6000022eb890 UIImageView:0x7fdd1f01efc0.height == 50 (active)>",
"<NSLayoutConstraint:0x6000022c7480 V:|-(16)-[UIImageView:0x7fdd1f01efc0] (active, names: '|':UITableViewCellContentView:0x7fdd1f01eb00 )>",
"<NSLayoutConstraint:0x6000022c74d0 V:[UIImageView:0x7fdd1f01efc0]-(16)-| (active, names: '|':UITableViewCellContentView:0x7fdd1f01eb00 )>",
"<NSLayoutConstraint:0x6000022c1d10 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fdd1f01eb00.height == 82.3333 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x6000022eb890 UIImageView:0x7fdd1f01efc0.height == 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.
If you are setting the height for the ImageView then no need to set the bottom constraint and even top constraint. Remove both bottom and top constraint and add the constraint to centerY i.e. center vertically the image view to the container.
The reason why you are getting this issue is because it is ambiguous as which constraint to satisfy whether the height constraint of the Image view or top/ bottom constraint.

Can QML drag-and-drop mechanic work without drag item moving?

I have a listview and a rectangle on top of it. The ListView's delegates have DropAreas in them and the rectangle has drag enabled on Y axis with its relevant properties (hotspot, target).
When I move the rectangle up and down on the ListView, the DropAreas of the delegates are registering onEntered signals. Working as intended.
However, I am using SmoothedAnimation to scroll the list up and down when the rectangle is at the most top and bottom coordinates (list.y = 0 and list.height). So the rectangle is not moving, and the DropAreas of the list's delegates are moving under it. In that case, the onEntered is not registered because there is no dragging, the rectangle is completely still and although its hotspot is entering and leaving the DropAreas, there is no interaction.
This is because dragging mechanic is sending events all the time when moving and any DropAreas it comes inside can register the event. In my case there is no dragging and therefore no events.
Question: Can drag events be manually activated? Can I somehow simulate drag?
At first, you should change the drag.target: parent to drag.target: this. In this way instead of dragging the parent item, you drag only the mouseArea. After that, you should grab an image from the item that you want to drag. The code is here:
Rectangle {
id: rec
width: 100
height: 100
Drag.active: dragArea.drag.active
Drag.dragType: Drag.Automatic
Drag.supportedActions: Qt.CopyAction
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: this
onPressed:{
parent.grabToImage(function(result) {
parent.Drag.imageSource = result.url
})
}
}
}
I have managed to induce drag events by manually changing the hotSpot property of the rectangle above the list. QML Drag documentation says:
Changes to hotSpot trigger a new drag move with the updated position.
So I have done this every time Listview contentY changes (vertical scrolling happens)
onContentYChanged:
{
rectangle.Drag.hotSpot.x += 0.0001
rectangle.Drag.hotSpot.x -= 0.0001
}
In hindsight, however, this is a 'hacky' solution. hotSpot property is a QPointF class property (link). This means it can be set using various methods (setX, setY, rx, ry..). For example, this:
rectangle.hotSpot += Qt.point(0,0)
or
rectangle.hotSpot = Qt.point(rectangle.hotSpot.x,rectangle.hotSpot.y)
should work in theory by resetting the hotSpot point when contentY changes, but testing revealed it unfortunately does not trigger a new drag move. (bug or intended, I don't know)
Now some of you that are more into Qt and QML might know more about this and how to properly adress the issue, but the above solution works for me and after testing everything I could imagine to get a cleaner solution, I settled on it.

Swift Autolayout warnings and other warnings i do not understand

The app allows users to post images/follow others etc.
So it works fine but i get the following warnings:
(I know some has to do with AutoLayout constraints but how do i know which is causing the problems?)
2015-07-05 17:19:37.701 Pixym[1271:72192] CUICatalog: Invalid asset name supplied:
2015-07-05 17:19:37.702 Pixym[1271:72192] Could not load the "" image referenced from a nib in the bundle with identifier "HP.Pixym"
2015-07-05 17:19:37.705 Pixym[1271:72192] 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)
(NSLayoutConstraint:0x7fa83b822a40 H:[UIImageView:0x7fa83b8529a0(300)],
NSLayoutConstraint:0x7fa83b85ccb0 H:[UIImageView:0x7fa83b8529a0]-(10)-| (Names: '|':UITableViewCellContentView:0x7fa83b871ff0 ),
NSLayoutConstraint:0x7fa83b8643d0 H:|-(10)-[UIImageView:0x7fa83b8529a0] (Names: '|':UITableViewCellContentView:0x7fa83b871ff0 ),
NSLayoutConstraint:0x7fa83b80ab00 'UIView-Encapsulated-Layout-Width' H:[UITableViewCellContentView:0x7fa83b871ff0(375)])
Will attempt to recover by breaking constraint
NSLayoutConstraint:0x7fa83b822a40 H:[UIImageView:0x7fa83b8529a0(300)]
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in UIKit/UIView.h may also be helpful.
Any help will be appreciated.
From the constraints, it seems you have an imageView with a width of 300 and a left and right padding of 10. That would work fine on iPhone 5(where the screen width is 320) but it will crash on iPhone 6/ 6 Plus because there the width is bigger.
What you need to do, is figure out how would you want the image to look like on all screens. Is the 10 pixels padding more important than the width or you would like it to always have a width of 300?
If you want the width, remove the other 2 constraints and add a center horizontal in container constraint for the image.
In the other case, just remove the width constraints and all should work.
Good luck!

Error: Unable to simultaneously satisfy constraints

I get this error:
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)
(
"<NSLayoutConstraint:0x1600aec0 V:[UIView:0x102021d0]-(0)-| (Names: '|':UIView:0x1600a980 )>",
"<NSLayoutConstraint:0x1600ae80 V:|-(494)-[UIView:0x102021d0] (Names: '|':UIView:0x1600a980 )>",
"<NSAutoresizingMaskLayoutConstraint:0x1600e8a0 h=-&- v=-&- UIView:0x1600a980.height == UIWindow:0x9e0ea30.height>",
"<NSAutoresizingMaskLayoutConstraint:0x9e2d130 h=--- v=--- V:[UIWindow:0x9e0ea30(480)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x1600aec0 V:[UIView:0x102021d0]-(0)-| (Names: '|':UIView:0x1600a980 )>
Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in
<UIKit/UIView.h> may also be helpful.
the view that generates this error has 4 constrains for left/right/top/bottom and I can not delete any of them.
I have tried:
[View setTranslatesAutoresizingMaskIntoConstraints:NO];
with no result.
do you have any idea how to fix this?
Thank you!
The problem is in the vertical layout.
<NSAutoresizingMaskLayoutConstraint:0x9e2d130 h=--- v=--- V:[UIWindow:0x9e0ea30(480)]>
Autoresizing mask for a window. Fixed margins and size. You can't change this.
<NSAutoresizingMaskLayoutConstraint:0x1600e8a0 h=-&- v=-&- UIView:0x1600a980.height == UIWindow:0x9e0ea30.height>
Autoresing mask (fixed margins, resizable content). Probably the view of your controller. The height is 480 (set to be equal to the size of the window). Nothing to fix here.
<NSLayoutConstraint:0x1600aec0 V:[UIView:0x102021d0]-(0)-| (Names: '|':UIView:0x1600a980 )>
<NSLayoutConstraint:0x1600ae80 V:|-(494)-[UIView:0x102021d0] (Names: '|':UIView:0x1600a980 )>
You can notice that both constraints are doing something with the same view ([UIView:0x102021d0]) and have the same second view as a parameter (UIView:0x1600a980). The second view is our controller's view.
The two constraints define distances from edges of the second view. The first defines bottom (0). The second one defines top (494). If the superview's size is 480, that means [UIView:0x102021d0] would have height equal to -14 which triggers that exception.
How to fix it? Well, change the 494 constraint to the correct value. It's possible you don't even want the "top" constraint, maybe you want a fixed height instead.
How did the problem arise? You probably created your constraints for iPhone 5 and then you tried to run the app with iPhone 4. If you change the simulated size in your xib to iPhone 4, you should see the problem immediately.
There are still views that have translatesAutoresizingMaskIntoConstraints set to YES, apparently, otherwise you wouldn't be getting that message. It's probably the superview of the view that's giving you problems. Make sure that it also doesn't translate its autoresizing masks to constraints.

NSLayoutConstraint Error: making full subview [duplicate]

This question already has answers here:
Xcode 4.4 constraint errors
(2 answers)
Closed 9 years ago.
I'm making full-frame subview, ( subview's frame = superview's bound )
I made expansion like following
[self addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"H:|-0-[subview]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(subview)]];
[self addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|-0-[subview]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(subview)]];
But run time error occus, shown the following error.
"<NSAutoresizingMaskLayoutConstraint:0x1001bb700 h=--& v=--& H:[IUView:0x10015dcc0(960)]>",
"<NSLayoutConstraint:0x1001911d0 H:|-(0)-[IUBGView:0x1001783f0] (Names: '|':IUView:0x10015dcc0 )>",
"<NSLayoutConstraint:0x1001910e0 H:[IUBGView:0x1001783f0]-(0)-| (Names: '|':IUView:0x10015dcc0 )>",
"<NSLayoutConstraint:0x10017bbf0 H:|-(0)-[NSImageView:0x100160050] (Names: '|':IUBGView:0x1001783f0 )>",
"<NSLayoutConstraint:0x10015d7f0 H:[NSImageView:0x100160050]-(0)-| (Names: '|':IUBGView:0x1001783f0 )>",
"<NSAutoresizingMaskLayoutConstraint:0x1001a6a80 h=--& v=--& H:[NSImageView:0x100160050(0)]>"
Will attempt to recover by breaking constraint
Set the NSUserDefault NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints to YES to have -[NSWindow visualizeConstraints:] automatically called when this happens. And/or, break on objc_exception_throw to catch this in the debugger.
Can you explain what I missed?
It appears that you're not turning of the 'translatesAutoresizingMaskInotConstraints' feature of the views you've created by hand.
someView.translatesAutoresizingMaskIntoConstraints = NO;
If you don't set that to NO then iOS converts the springs-and-struts (e.g. auto resizing mask) settings to constraints. Those constraints are conflicting with the ones you're making with the visual format language.
Anytime you see the class 'NSAutoresizingMaskLayoutConstraint' in the constaints error output then you can be sure you haven't turned off translates.
Good practice is that on every view you create programmatically, you also turn of translates.