How to programmatically add constraint center with multiplier - ios

I do use multiplier with center constraints in the storyboard, now I want to do the same programmatically but can't figure out how to.
No, this thread does not help since the accepted answer is a workaround that would not auto resize if the superview size happens to change later on.
The storyboard center X constraint:
What I've tried without success:
// Does not exist
buttonLeft.centerXAnchor.constraint(equalTo: centerXAnchor, multiplier: 0.5).isActivate = true
// error shown:
// Cannot convert value of type 'NSLayoutXAxisAnchor' to expected argument type 'NSLayoutConstraint.Attribute'
let newConstraint = NSLayoutConstraint(item: self, attribute: centerXAnchor, relatedBy: .equal, toItem: buttonLeft, attribute: centerXAnchor, multiplier: 0.5, constant: 0)
Is it possible?
Yes: how?
No: do you have any explaination of why wouldn't it be possible programmatically? Does this thing is a syntaxic sugar hidding something more complexe? I'm lost..
And yep, it works as expected when this constraint is set using the storyboard

So it's possible, I missused the centerXAnchor instead of using .centerX
Also the order in which I called each item was not correct:
// Not Working
NSLayoutConstraint(item: self, attribute: centerXAnchor, relatedBy: .equal, toItem: buttonLeft, attribute: centerXAnchor, multiplier: 0.5, constant: 0)
// Working
NSLayoutConstraint(item: buttonLeft, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 0.5, constant: 0)
Though I could not find any way to create the constraint using the anchors methods.

Try using self.view.translatesAutoresizingMaskIntoConstraints = false before adding the constraints programmatically.

Related

Why does my button change padding in the iOS simulator?

I am trying to add a button to a view in my iOS app. In the Main.storyboard file the button appears as this:
However, whenever I start the simulator the button appears as:
If it helps, I have the button paired to a custom class that consists of:
import UIKit
class RoundedButton: UIButton {
override func awakeFromNib() {
super.awakeFromNib()
layer.borderWidth = 1
layer.borderColor = UIColor.blue.cgColor
contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
}
}
But I do not believe this is the cause of the issue. I think the problem stems from my lack of understanding of how scaling works in xCode but I am unable to find any resources on how to fix this issue.
Thanks!
Add constraints to your button and check. It will be perfect if you add the necessary constraints.
Constraints are used to tell devices where objects should be and their sizes, even with different devices, you can create a pattern. Remember you always have to configure X, Y, width and height so your elements are placed perfectly. Except for labels, which sometimes doesn't require width and height constraints.
For your button, adding constraints to align horizontally, vertically, width and height should work.
Add necessary constraints for the button. you can add in storyboard or programmatically.
In storyboard, you can add constraints like this:
For programmatically:
let horConstraint = NSLayoutConstraint(item: yourButton!, attribute: .centerX, relatedBy: .equal,
toItem: view, attribute: .centerX,
multiplier: 1.0, constant: 0.0)
let verConstraint = NSLayoutConstraint(item: yourButton!, attribute: .centerY, relatedBy: .equal,
toItem: view, attribute: .centerY,
multiplier: 1.0, constant: 0.0)
let widConstraint = NSLayoutConstraint(item: yourButton!, attribute: .width, relatedBy: .equal,
toItem: view, attribute: .width,
multiplier: 0.95, constant: 0.0)
let heiConstraint = NSLayoutConstraint(item: yourButton!, attribute: .height, relatedBy: .equal,
toItem: view, attribute: .height,
multiplier: 0.95, constant: 0.0)
view.addConstraints([horConstraint, verConstraint, widConstraint, heiConstraint])

FSCalendar date not aligned properly

When I first load my calendar, the layout become misaligned (refer to image 1). After physically rotating my device to landscape and back to portrait, it fix itself. (refer to image 2)
Anyone have any idea how to fix this issue? I do not know where to start to find the issue that caused this to happen.
Side note: (not sure if this have anything to do with the issue.)
the page before this also have another FSCalendar.
this affected fscalendar is inside a scrollview with constraint set to height = 0.4 of superview, width with left right margin of 8, and center x align to superview.
I had the same issue (and just like for you, rotating the device would fix it).
I was able to fix my problem by changing the layout constraints and setting the FSCalendar's translatesAutoresizingMaskIntoConstraints to false (I had created the FSCalendar programmatically).
In the end, I put the FSCalendar inside another UIView and set it up like this:
calendarView.translatesAutoresizingMaskIntoConstraints = false
calendarContainer.addSubview(calendarView)
[NSLayoutConstraint(item: calendarView, attribute: .top, relatedBy: .equal, toItem: calendarContainer, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: calendarView, attribute: .bottom, relatedBy: .equal, toItem: calendarContainer, attribute: .bottom, multiplier: 1, constant: 0),
NSLayoutConstraint(item: calendarView, attribute: .leading, relatedBy: .equal, toItem: calendarContainer, attribute: .leading, multiplier: 1, constant: 0),
NSLayoutConstraint(item: calendarView, attribute: .trailing, relatedBy: .equal, toItem: calendarContainer, attribute: .trailing, multiplier: 1, constant: 0)
].forEach({ $0.isActive = true })

Why does iOS 8 hate my AutoLayout but iOS 9 loves it?

I am initialising a view infoScreen and adding it as a subview of the screen with its bottom, left and right constraints set like this:
let left = NSLayoutConstraint(item: infoScreen, attribute: .Left, relatedBy: .Equal, toItem: view, attribute: .LeftMargin, multiplier: 1, constant: 0)
let right = NSLayoutConstraint(item: infoScreen, attribute: .Right, relatedBy: .Equal, toItem: view, attribute: .RightMargin, multiplier: 1, constant: 0)
var yConstraint: NSLayoutConstraint!
if (point.y < halfOfScreen) {
yConstraint = NSLayoutConstraint(item: infoScreen, attribute: .Top, relatedBy: .Equal, toItem: highlightedView, attribute: .CenterY, multiplier: 1, constant: radius + stalkLength)
}
else {
// This gets called the first time round.
yConstraint = NSLayoutConstraint(item: infoScreen, attribute: .Bottom, relatedBy: .Equal, toItem: highlightedView, attribute: .CenterY, multiplier: 1, constant: -radius - stalkLength)
}
view.addConstraints([left, right, yConstraint])
as well as it's height being set.
Then after a button within infoScreen is clicked, I'm calling infoScreen.removeFromSuperview().
Then the same function is used to reinitialise infoScreen with different parameters, and add it to the screen. However, this time it has its top constraint set instead of the bottom constraint.
In iOS 9 this works perfectly, however in iOS 8, it acts as if the bottom constraint is still set and messes up the view. If I run the code so that it never has the bottom constraint set (essentially skipping over the first run of the initialisation function), then it works fine in iOS 8. What could be causing this?

removeConstraint() not removing constraint

I have a weird problem. I want to change a constraint in certain conditions, but removeConstraint doesn't work. The constraint doesn't get removed.
Here's the code:
backButton.translatesAutoresizingMaskIntoConstraints = false
view.removeConstraint(constLabelTop)
let constNew = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: backButton, attribute: .CenterY,multiplier: 1, constant: 0)
view.addConstraint(constNew)
The constraint constLabelTop is a constraint which sets the top of the label a few points above the backButton. Why doesn't it work?
The new constraint clashes with the old one and the backButton gets squashed.
I tried backButton.removeConstraint too and didn't work either.
Try this:
backButton.translatesAutoresizingMaskIntoConstraints = false
constLabelTop.active = false
NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: backButton, attribute: .CenterY,multiplier: 1, constant: 0).active = true
self.view.layoutIfNeeded()

How to set UIImageView in the center of screen horizontally or vertically with Swift, but no more StoryBoard

I am trying to put an UIImageView on the upper center of screen horizontally which is coding in the viewDidLoad( ). And I have two pre-plans, which means I do not know the specify functions or APIs.
1). I want to set a variable which equal to the half of screen's width. And I know it gonna work with something about 'bounds' or 'frame'. Pathetically, I do not know those specify function or parameters.
2). In order to make sure the resolution, I want to figure out the currentDevice. After that, I can set UIImageView with CGRectMake((resolution.x)/2, y, length, width). Is there any function can confirm the currentDevice?
And I think the first one is more efficient than the second one.
A big appreciate for your help and guidance.
Ethan Joe
I would suggest to use autolayout:
var imageView = UIImageView()
imageView.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(imageView)
// Create the constraints and add them to a Array
var constraints = [AnyObject]()
// This constraint centers the imageView Horizontally in the screen
constraints.append(NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterX, multiplier: 1.0, constant: 0.0))
// Now we need to put the imageView at the top margin of the view
constraints.append(NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TopMargin, multiplier: 1.0, constant: 0.0))
// You should also set some constraint about the height of the imageView
// or attach it to some item placed right under it in the view such as the
// BottomMargin of the parent view or another object's Top attribute.
// As example, I set the height to 500.
constraints.append(NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 500.0))
// The next line is to activate the constraints saved in the array
NSLayoutConstraint.activateConstraints(constraints)
This code horizontally centers the imageView in every device. I suggest you investigating AutoLayout, it's a nice feature.
Here's a nice link where you can start with it:
Learning to love Auto Layout... Programmatically
So, the best solution to this would be to utilize auto layout.
Say your UIImageVew is defined as var imageView = UIImageView!.
Then you would do the following.
var centerXConst = NSLayoutConstraint(item: imageView, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 1)
var centerYConst = NSLayoutConstraint(item: imageView, attribute: .CenterY, relatedBy: .Equal, toItem: self.view, attribute: .CenterY, multiplier: 1, constant: 1)
self.view.addLayoutConstraints([centerXConst, centerYConst])
What you are doing is setting the center of the imageView on the x and y axis respectively to the same as the center of the view on the x and y axis respectively.
To find the width of the view as you proposed in 1), do the following:
var screenWidth = self.view.bounds.width

Resources