Why are NSLayoutConstraints ignored? - ios

I am experiencing a misunderstanding of mechanics of iOS Layout Constraints. See the code I placed inside viewDidLoad listed below.
var btn = UIButton()
btn.setTitle("i am a button", forState: UIControlState.Normal)
btn.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
btn.backgroundColor = UIColor.lightGrayColor()
btn.sizeToFit()
view.addSubview(btn)
view.addConstraint(
NSLayoutConstraint(item: view,
attribute: NSLayoutAttribute.CenterX,
relatedBy: NSLayoutRelation.Equal,
toItem: btn,
attribute: NSLayoutAttribute.CenterX,
multiplier: 1.0,
constant: 0.0))
view.addConstraint(
NSLayoutConstraint(item: view,
attribute: NSLayoutAttribute.CenterY,
relatedBy: NSLayoutRelation.Equal,
toItem: btn,
attribute: NSLayoutAttribute.CenterY,
multiplier: 1.0,
constant: 0.0))
It seems to me my intention is clear. I want to see a button at the center of a device's screen. But I can see only the following picture though.
And I have an output in project’s console so scary I cannot understand a thing from it.
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) (
"",
"",
"",
"
(Names: '|':UIWindow:0x7fd318551080 )>" )
Will attempt to recover by breaking constraint
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints
to catch this in the debugger. The methods in the
UIConstraintBasedLayoutDebugging category on UIView listed in
may also be helpful. 2015-04-28 23:46:04.516
ConsTest[5966:248434] 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) (
"",
"",
"",
"
(Names: '|':UIWindow:0x7fd318551080 )>" )
Will attempt to recover by breaking constraint
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints
to catch this in the debugger. The methods in the
UIConstraintBasedLayoutDebugging category on UIView listed in
may also be helpful.
Looks like the constraints are treated contradictory and thus ignored at all. I cannot really point out why I can’t just create a button and place it at the center programmatically. Any relevant instruction is much appreciated.

On your UIButton (btn) set translatesAutoresizingMaskIntoConstraints = false
E.g.
btn.translatesAutoresizingMaskIntoConstraints = false
Recommended reading: Adopting Auto Layout

Related

Could not find relevant edges for attributes

I get the following error:
Could not resolve symbolic constant for constraint, because: Could not
find relevant edges for attributes: centerX and centerX.
Use a symbolic
breakpoint at
NSLayoutConstraintFailedToFindDefaultResolvedValueForSymbolicConstant
to debug.
If I add a breakpoint at NSLayoutConstraintFailedToFindDefaultResolvedValueForSymbolicConstant it stops at this line:
[self.customNavigationBar.widthAnchor constraintEqualToAnchor:self.view.widthAnchor].active = YES;
This line is called within the viewDidLoad of the view controller. customNavigationBar is a UIView loaded from a nib which already have been added as subview to self.view.
If I try to print out the anchors I am using everything seems ok:
(lldb) po self.customNavigationBar.widthAnchor
<NSLayoutDimension:0x17446cc80 "UIView:0x10115c160.width">
(lldb) po self.view.widthAnchor
<NSLayoutDimension:0x170667080 "UIView:0x1012ae550.width">
This error comes from your choice of constructor for the NSLayoutConstraint.
You probably have something like this:
view.topAnchor.constraint(equalToSystemSpacingBelow: otherView.centerYAnchor, multiplier: 0.25).isActive = true
But you should construct it like this:
let constraint = NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: otherView, attribute: .centerY, multiplier: 0.25, constant: 1)
constraint.isActive = true

How to properly resize the most outside view in a custom keyboard extension ViewController using swift 3?

I have a function that sets the height of a custom keyboard extension, depending on the phone. I originally just tried this in viewDidLoad():
self.view.heightAnchor.constraint(equalToConstant: 100)
This didn't seem to work, so I made a function:
func updateHeightOfView() {
var currentKeyboardInView: String!
if currentViewHeightConstraint != nil {
view.removeConstraint(currentViewHeightConstraint!)
}
currentViewHeightConstraint = NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1.0, constant: desiredHeight)
view.addConstraint(currentViewHeightConstraint!)
}
that way when the screen changes it's orientation, I resize the view. The second block of code works perfectly, but it throws warnings of layoutConstraints, so I was wondering why the first block of code isn't working, and if there is an easier way to UPDATE constraints of the height property of a view rather than add and remove them. This view is the most outside view in the viewController.
Here's the warning the second block spits out:
[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:0x608000298b00 App.KeyboardAccessoryView:0x7fdc00b1bfe0.height == 258 (active)>",
"<NSLayoutConstraint:0x600000297e80 'UIView-Encapsulated-Layout-Height' App.KeyboardAccessoryView:0x7fdc00b1bfe0.height == 216 (active)>"
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x608000298b00 App.KeyboardAccessoryView:0x7fdc00b1bfe0.height == 258 (active)>
As much detail you given here according to this I think where ever you set height of this view it is not static constant value but in view didload you are setting constant value for its height. So that's by it is not working.
In second block you are getting warning because may be your view is getting height from more than one way. To check this in updathHeight method just remove the constraint , don't add and try to run.
Exact solution could be given only looking on your constraints.

How to change size of an MKMapView in Swift?

I can't seem to change the size of my MKMapView in Swift. How would one go on about it?
I've tried two different methods but without any luck:
var rect: CGRect = self.view.frame;
rect.origin.y = 0;
self.mapView.frame = rect;
and one where I used constraints and autolayout but it made the app crash. Any ideas?
EDIT:
When I write this code it doesn't crash but writes some warnings in the output:
let height = UIScreen.mainScreen().bounds.height
let width = UIScreen.mainScreen().bounds.width
let widthConstraint = NSLayoutConstraint(item: mapView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: width)
self.view.addConstraint(widthConstraint)
let heightConstraint = NSLayoutConstraint(item: mapView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: height)
self.view.addConstraint(heightConstraint)
The output says:
2016-03-09 18:43:02.697 Map[19782:3177712] 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.
(
"",
""
)
Will attempt to recover by breaking constraint
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints
to catch this in the debugger. The methods in the
UIConstraintBasedLayoutDebugging category on UIView listed in
may also be helpful. Message from debugger:
Terminated due to signal 15
I don't really understand this, any ideas?
In this case you should use
self.mapView.addConstraint(widthConstraint)
and
self.mapView.addConstraint(heightConstraint)
You are trying to add a constraint that belongs to the mapView to its superview, that's not the way it's supposed to be. If you were adding a vertical distance between the mapview and another view you would add it to the superview, but not in this case.
For the constraint warning you try to add constraint without disabling the autorisizing mask into constraint translation.
Try adding this line:
mapView.translatesAutoresizingMaskIntoConstraints = false
Regards

Adding view to UIAlertController result by breaking constraint on iPad

Im building slider inside UIAlertController and it actually worked fine on iPhone but gives breaking constraint error on iPad, i gave the alert 140 of height as constraint before presenting.
Here is my code:
let alertController = UIAlertController(title:"Title", message: "", preferredStyle: UIAlertControllerStyle.Alert)
let slider = UISlider(frame: CGRectMake(35, 50, 200, 20))
alertController.view.addSubview(slider)
let height:NSLayoutConstraint = NSLayoutConstraint(item: alertController.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 140)
alertController.view.addConstraint(height);
alertController.addAction(UIAlertAction(title: "close", style: UIAlertActionStyle.Cancel, handler: { (error) -> Void in
}))
self.presentViewController(alertController, animated: true, completion: nil)
The 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:0x7b555900 V:[_UIAlertControllerView:0x788d2a60'Title'(140)]>",
"<NSLayoutConstraint:0x789db3f0 V:[_UIAlertControllerView:0x788d2a60'Title'(1024)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x789db3f0 V:[_UIAlertControllerView:0x788d2a60'Title'(1024)]>
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.
Okay, I have an answer, but you’re not going to like it.
If you do the following (with no constraints added):
print("Alert frame" + String(alertController.view.frame))
self.presentViewController(alertController, animated: true, completion: nil)
You will get the following:
Alert frame(0.0, 0.0, 768.0, 1024.0)
Which just happens to be the iPad Air’s width and height in portrait mode. Okay, that’s obviously not the views width and height. Let’s modify our code a bit.
self.presentViewController(alertController, animated: true)
{
print("Alert frame" + String(alertController.view.frame))
}
This time I get the following:
Alert frame(0.0, 0.0, 300.0, 85.5)
Please note that I have two “\n\n” in my title. So let us ASSUME they are doing something funky prior to presenting it (remember Apple tells us this is an opaque class).
So let’s add the following:
self.presentViewController(alertController, animated: true)
{
let height:NSLayoutConstraint = NSLayoutConstraint(item: alertController.view,
attribute: NSLayoutAttribute.Height,
relatedBy: NSLayoutRelation.Equal,
toItem: nil,
attribute: NSLayoutAttribute.NotAnAttribute,
multiplier: 1,
constant: self.view.frame.height * 1.20)
alertController.view.addConstraint(height);
}
Now, cross our fingers for luck, and see what happens.
Unable to simultaneously satisfy constraints.
This suggests, to me, that Apple has constraints on the iPad that it does not on the iPhone. When we toss in our height constraint we have set up a situation where the internal constraint code is attempting to solve for two conflicting commands. As such, it can only do so by breaking the constraints.
I’m using .ActionSheet but I’m getting the same issue. It appears that Apple doesn’t use constraints for the iPhone. If you aren’t building a universal app, then you should be fine.
However, and this is important, Apple could impose constraints on the iPhone in the future which could cause the same issue.
The bottom line is this:
The UIAlertController class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.
To me, Apple should be far more explicit and say, “We do not support modifications at all.” I suspect they think the “as-is” covers it, but as you have probably seen (as I have) many people don’t test all cases.
As such, I plan to look for a third party version that supports both the iPhone and iPad (see UIAlertController - add custom views to actionsheet - it is a similar issue.
Wasting my time on something that could break in an interim release of iOS is not worth it.

How to apply auto layout properly

I have set of images(thumbs) in UITableviewcell. When tapping on each image, a popup(custom view) will be displayed which is a UISCrollview. i am adding all images(big) in Scroll View. So user can scroll to see images.
I am adding UISCrollView to RootViewController's view. so that it covers the entire screen. Below is my code
My Code:
self.mainView = self.superview?.window?.rootViewController?.view
imageScrollView = UIScrollView(frame: CGRectMake(0, 0, self.mainView!.frame.size.width, self.mainView!.frame.size.height))
imageScrollView.delegate = self
self.mainView.addsubview(imageScrollView)
Constraints:
self.mainView!.addConstraint(NSLayoutConstraint(item: imageScrollView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self.mainView!, attribute: NSLayoutAttribute.CenterX, multiplier: 1.0, constant: 0.0))
self.mainView!.addConstraint(NSLayoutConstraint(item: imageScrollView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self.mainView!, attribute: NSLayoutAttribute.CenterY, multiplier: 1.0, constant: 0.0))
I got the error in console:
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:0xab1090 h=--- v=--- H:[UIWindow:0xa724f0(768)]>",
"<NSLayoutConstraint:0x1133f450 UIScrollView:0x115723a0.centerY == UIView:0xa49fe0.centerY>",
"<NSAutoresizingMaskLayoutConstraint:0x483cc70 h=--& v=--& UIScrollView:0x115723a0.midY == + 512>",
"<NSAutoresizingMaskLayoutConstraint:0x115b7290 h=-&- v=-&- UIView:0xa49fe0.width == UIWindow:0xa724f0.width>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x1133f450 UIScrollView:0x115723a0.centerY == UIView:0xa49fe0.centerY>
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.
2014-12-08 01:13:27.379 afipad[349:60b] 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:0xab10c0 h=--- v=--- V:[UIWindow:0xa724f0(1024)]>",
"<NSLayoutConstraint:0x1133f090 UIScrollView:0x115723a0.centerX == UIView:0xa49fe0.centerX>",
"<NSAutoresizingMaskLayoutConstraint:0x115b6dd0 h=--& v=--& UIScrollView:0x115723a0.midX == + 384>",
"<NSAutoresizingMaskLayoutConstraint:0x115b72f0 h=-&- v=-&- UIView:0xa49fe0.height == UIWindow:0xa724f0.height>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x1133f090 UIScrollView:0x115723a0.centerX == UIView:0xa49fe0.centerX>
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.
When i check with break point, i got UIWindow size as 768 and 1024 in both portrait and Landscape. When i rotate the screen from Portrait to Landscape, the "imageScrollView" size is 768(width) and 1024(height) instead of 1024x768. What is the actual cause? How can i resolve it.
There are a couple different conflicting things happening here.
First, adding a subview to the root ViewController's view probably isn't going to work because it breaks encapsulation on several levels. Instead, present a new view controller containing your scrollView -- either as a modal or by pushing from self.navigationController -- directly from your table cell.
Second, autolayout constraints on UIScrollviews are kinda counterintuitive. See https://developer.apple.com/library/ios/technotes/tn2154/_index.html for an explanation of how to set them up.
Third, you'll probably need to set translatesAutoresizingMaskIntoConstraints to FALSE in this new viewController. (It explains that in the document, too)
Also, see my sample project for some examples of how to put images and other things inside a scrollView using autolayout:
https://github.com/annabd351/AutolayoutTemplate

Resources