How Autolayout constraint First Item and Second Item works? - ios

If I have UIView with top 100 left 120 right 120 how exactly First Item and Second Item relationship work. After going through Apple document each relationship has a linear equation with an expression as.
firstItem.firstItemAttribute == secondItem.secondItemAttribute * multiplier + constant
With this equation for top leading constraint with relation
First Item Safe Area.Leading
Relation =
Second Item = MyView.Leading
Constant 120
with equation the First Item And Second Item I understood. But Problem for me in understanding when I do the reverse the second item constant changes to - 120 and layout has no effect after the change. Why negative has no effect and what is its use for?
Xcode provides a set of properties for FirstItem & SecondItem like leading, center, trailing when we need to switch this properties.

First Item = Safe Area.Leading --- that's the "left edge" of the Safe Area
Second Item = MyView.Leading --- that's the "left edge" of your view
So, "left edge" of the Safe Area to "left edge" of your view equals 120, or, your view is 120 pts from the Safe Area (to the right).
First Item = MyView.Leading --- that's the "left edge" of your view
Second Item = Safe Area.Leading --- that's the "left edge" of the Safe Area
So, "left edge" of your view to "left edge" of the Safe Area equals -120, or, the left edge of Safe Area is -120 pts from your view (to the left).
If you change -120 to 120, that would put the left edge of the Safe Area +120 pts, or 120 pts to the right, of your view's left edge, which would push the view off the screen to the left.
Edit:
For a little more clarity...
With "SafeArea.Leading -> myView.Leading", you are saying "put myView's left edge 120-pts from the left edge of the Safe Area"
When you swap them to "myView.Leading -> SafeArea.Leading", you are saying "put SafeArea's left edge minus 120-pts from the left edge of myView".
In general, when using Interface Builder, you leave the order alone... because you are visually laying out your elements, and IB knows how to define the constraints.
More often where you will see a difference, is when setting up constraints in code.
For example, to put a subview (red) inside a containing view (blue), with 20-pts padding on all four sides like this:
your code might look like this:
let myContainerView = UIView()
myContainerView.translatesAutoresizingMaskIntoConstraints = false
myContainerView.backgroundColor = .blue
// add container view to self view
view.addSubview(myContainerView)
// constrain container view center X and Y, width and height both 240-pts
NSLayoutConstraint.activate([
myContainerView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0),
myContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0.0),
myContainerView.widthAnchor.constraint(equalToConstant: 240.0),
myContainerView.heightAnchor.constraint(equalToConstant: 240.0),
])
let myInnerView = UIView()
myInnerView.translatesAutoresizingMaskIntoConstraints = false
myInnerView.backgroundColor = .red
// add inner view to container view
myContainerView.addSubview(myInnerView)
// constrain inner view with 20-pts padding on all four sides
NSLayoutConstraint.activate([
// top and left are 20-pts from superview top and left
myInnerView.topAnchor.constraint(equalTo:
myContainerView.topAnchor, constant: 20.0),
myInnerView.leadingAnchor.constraint(equalTo:
myContainerView.leadingAnchor, constant: 20.0),
// bottom and right are *minus* 20-pts from superview bottom and right
myInnerView.bottomAnchor.constraint(equalTo:
myContainerView.bottomAnchor, constant: -20.0),
myInnerView.trailingAnchor.constraint(equalTo:
myContainerView.trailingAnchor, constant: -20.0),
])
You will note that the trailing and bottom constraints of the inner view must be negative, because you want them to be 20-pts away from the trailing and bottom edges of the container view.

Related

UIKit: Constraints with respecting NavBar and ignoring safe area at the bottom

I'm following by one of the video of Paul Hudson and trying to recreate detail screen with full screen image. By following the video I set up constraints to Reset to suggested contains but I have different values compering to video. I tried to play around with settings but can't get the expected result...
Constraints:
Image View.top = topMargin - 44
Image View.centerX = centerX
Image View.centerY = centerY
Image View.leading = Safe Area.leading
Result:
Expected:
Question: How to set up constraints to respect NavigationBar and took all other place in the screen, like in expected image?
Assuming your VC is embedded in a navigation controller, you basically want to constraint the left, right and bottom of the image view to be equal to its superview, and the top of the image view to the top layout guide:
You should select the image view, and add the constraints using this pop up:
Click on all four of the thingys I circled. If the first or second items of the constraints added are incorrect, change them by selecting the constraint and using the drop down here:
Alternatively, just add them with code:
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
imageView.leftAnchor.constraint(equalTo: view.leftAnchor),
imageView.rightAnchor.constraint(equalTo: view.rightAnchor),
imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
Based on answer from Sweeper created constraints in Storyboard:
Image View.leading = leading
Image View.top = Safe Area.top
trailing = Image View.trailing
bottom = Image View.bottom

How can I tell if an iPhone's home indicator is present or not in xcode? [duplicate]

This question already has answers here:
How to detect if the device (iphone) has physical home button?
(2 answers)
Closed 9 months ago.
I have placed a button at the bottom of the safe area.
On iPhone X and later devices, it is placed well above a certain margin, but in the case of an iPhone with a home button, it is attached to the bottom.
So, I would like to set a separate constraint only on iPhones with a home button to leave a certain margin.
iPhoneSE
iPhone 13 Pro
You don't need to detect the home button... in fact, that's probably not what you want to do anyway.
Another approach is to use two bottom constraints, with different priorities.
You can constrain the bottom of the button to the bottom of the safe area, and give that constraint a less-than-required priority.
You can then apply another constraint, this time at a minimum distance from the bottom of the view.
Here's an example:
class BottomPaddingViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let safeAreaView = UIView()
safeAreaView.backgroundColor = .red
safeAreaView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(safeAreaView)
let btn = UIButton()
btn.backgroundColor = .systemBlue
btn.setTitle("Button", for: [])
btn.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(btn)
let g = view.safeAreaLayoutGuide
// bottom constraint for the button
// to the safe area bottom
// with less-than-required priority
let bConstraint = btn.bottomAnchor.constraint(equalTo: g.bottomAnchor)
bConstraint.priority = .required - 1
NSLayoutConstraint.activate([
// constrain the red view to the safe area bottom
safeAreaView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
safeAreaView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
safeAreaView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
safeAreaView.heightAnchor.constraint(equalToConstant: 40.0),
// constrain button 200-pts wide, centered horizontally
btn.widthAnchor.constraint(equalToConstant: 200.0),
btn.heightAnchor.constraint(equalToConstant: 40.0),
btn.centerXAnchor.constraint(equalTo: g.centerXAnchor),
// and bottom AT LEAST 20-points from the bottom of the VIEW
btn.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor, constant: -20.0),
// activate the button's safe area bottom constraint
bConstraint,
])
}
}
When running on a phone without a physical button (iPhone 12, for example) it looks like this:
we see that both the blue button and the red view are bottom-constrained to the safe area.
When running on a phone with a physical button (iPhone 8, for example) it looks like this:
the red view is still constrained to the safe area, but the blue button keeps its minimum distance from the view bottom.

How to set Safe Area Layout for new IPhone Devices in swift

I have created a simple view.Xib file, if internet connection interrupts or disconnects for any reason my view will be displayed at the bottom.
For this I have set programmatically NSLayoutConstraint.
If I use SafeAreaLayout it gives spaces at the bottom of every new iPhone devices like (iPhone XR, 11, Pro or Pro max).
If I don't use SafeAreaLayout then view at bottom not properly displayed.
In all other devices (iPhone 7, 8 or plus) with SafeAreaLayout it works properly.
How can I set view properly at the bottom without space?
My Code:
let viewW = offlineView.fromNib()
view.addSubview(viewW)
viewW.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
viewW.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
viewW.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
viewW.topAnchor.constraint(equalTo: self.view.bottomAnchor,constant: -25),
viewW.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
])
let viewW = offlineView.fromNib()
view.addSubview(viewW)
viewW.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
viewW.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
viewW.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
viewW.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor,constant: -25),
viewW.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
])
Screenshots attached:
SafeArea:
Without SafeArea:
Constraints of Red Circle:
You may want to try this approach...
Constrain the "dark" view:
Leading to superview Leading
Trailing to superview Trailing
Bottom to superview Bottom
no Height constraint
Then, add your "circle" view as a subview of darkView, and constrain:
Trailing to darkView Trailing: 4-pts
Top to darkView Top: 4-pts
Bottom to the root-view safe-area Bottom: 4-pts
and the label, also a subview of darkView, constrained:
Trailing to circle Trailing: 8-pts
CenterY to circle CenterY
Now...
Auto-layout will keep darkView's Bottom at the bottom of the screen, and darkView's Top 4-pts from Top of circle view.
Auto-layout will keep circle view's Bottom 4-pts from the Bottom of the view (when there's no soft-home-button) and 4-pts from the Bottom of the safe-area (when there is a soft-home-button).
Here's the results -- the yellow dashed line is the Safe-Area bounds.
on iPhone 8:
and on iPhone 11 Pro:
and how it looks in Storyboard:

Align an Icon to the top left of multiline UILabel

On the top left on a UILabel I want to align an Icon. This works file but if the Label has multiple lines the UIImage is aligned in the middle of the UILabel. There are option on interface builder such as first base line, but what I need is something like first line center Y. Is there something similar?
Actually there is a way of doing this! If you use AutoLayout this can be done with the following snippet:
// Aligns the icon to the center of a capital letter in the first line
let offset = label.font.capHeight / 2.0
// Aligns the icon to the center of the whole line, which is different
// than above. Especially with big fonts this makes a visible difference.
let offset = (label.font.ascender + label.font.descender) / 2.0
let constraints: [NSLayoutConstraint] = [
imageView.centerYAnchor.constraint(equalTo: label.firstBaselineAnchor, constant: -offset),
imageView.trailingAnchor.constraint(equalTo: label.leadingAnchor, constant: -10)
]
NSLayoutConstraint.activate(constraints)
The first constraint will display your icon at the Y center of the first line of your label. The second one puts your icon left of the label and creates a 10pt space between them.
Just put constraints as shown in the above image.
Hint: I made label's lines property value to 5 which supports upto 5 lines without any compromise.

How to center vertically labels in a view

I have 4 labels like this in a view:
The view hierarchy like this:
But if one of text in each label is empty, all of other labels should center vertically with the image.
For example: the albumDataLabel.text is empty, then userNameLabel, albumNameLabel, albumLocationLabel should center vertically with the image.
Somethings like this:
So how to do this, please point me to some approaches.
Set height constraint for every label and which label have not text
make it's height zero(from outlet of height constraint by setting constant to 0) at runtime.
Your constraint should be in linear hierarchy like first label's top should be pinned with it's supper view's top and last label's bottom should be pinned with superview's bottom and each and every label's bottom should be pinned with top of below label.
then you should set height constraint for view that contains all labels with constant (>=) of minimum height(least height of your view).
and centered vertically that view with your image view.
you can do this kind of setup!!
Since your 4 Labels are already in a view, you can set the labels' constraints to pin the first Label to the top, last Label the bottom and spacing in between to zero
Then select the view(withLabels) and your ImageView to align their vertical centers
Do not set a height value constraint for your labels nor the view
When one of your labels have an empty string, the height is automatically set to zero and hence 'hidden' so the view(withLabels) will shrink in height. All can be done in the interface builder, no coding necessary, it is just a matter of autolayout.
1) for your userNameLabel:
userNameLabel.leftAnchor.constraintEqualToAnchor(imageView.rightAnchor, constant: 10).active = true
userNameLabel.topAnchor.constraintEqualToAnchor(self.topAnchor, constant: 50).active = true
userNameLabel.widthAnchor.constraintEqualToConstant(220).active = true
userNameLabel.heightAnchor.constraintEqualToConstant(30).active = true
2) for your albumNameLabel:
albumNameLabel.widthAnchor.constraintEqualToConstant(220).active = true
albumNameLabel.heightAnchor.constraintEqualToConstant(30).active = true
albumNameLabel.topAnchor.constraintEqualToAnchor(userNameLabel.bottomAnchor, constant: 5).active = true
albumNameLabel.leftAnchor.constraintEqualToAnchor(imageView.leftAnchor, constant: 10).active = true
3) remember this:
self.addSubview(userNameLabel)
self.addSubview(albumNameLabel)
And go on in this way to all elements in your View.

Resources