Align an Icon to the top left of multiline UILabel - ios

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.

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 to vertically align two UILabels within one line?

I am trying to put two UILabels within one line: one UILable on left side, with text left-aligned, one UILabel on right side, with text right-aligned. Please see above image. They have different font sizes.
I used below auto layout constraints:
let labelHorizontalConstrains = NSLayoutConstraint.constraints(
withVisualFormat: "H:|-20-[nameLabel]-15-[birthDeathDateLabel]-20-|",
metrics: nil,
views: views)
allConstraints += labelHorizontalConstrains
But the result shows that they are not vertically aligned: The left UILabel is lower than the right UILabel. How to fix this?
You need to add a centerYAnchor constraint.
birthDeathDateLabel.centerYAnchor.constraint(equalTo: nameLabel.centerYAnchor).isActive = true
However, if you want it aligned with the base of the text, you should use a UIStackView.
let stackView = UIStackView(arrangedSubviews: [nameLabel, birthDeathDateLabel])
stackView.alignment = .firstBaseline
stackView.axis = .horizontal
// Add other stackview properties and constraints
you need to add a leading constraint and a height constraint to the right label. add a trailing and height constraint to the left label. then specify an equal widths constraint. also on the right label add the distance from the left label with a trailing constraint and for the left label add a leading constraint how far you want it from the right label.. much easier on storyboard. you could also use fit equally.. I can't remember the actual code, but it might have refreshed your memory. if I was too add that sort of constraint I would do it on a skeleton storyboard.

How to make a UITextView fill up the remaining space

I have a UIButton and UITextField side by side as follows.
I want the Add button to only have a width based on the content. And the text view shall take up the rest of the space. I have the following auto layout constraints.
private func setupLayout() {
newDeviceIdTextField.topAnchor.constraint(equalTo: deviceIdLabel.bottomAnchor, constant: 12).isActive = true
newDeviceIdTextField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12).isActive = true
newDeviceIdButton.topAnchor.constraint(equalTo: deviceIdLabel.bottomAnchor, constant: 12).isActive = true
newDeviceIdButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12).isActive = true
newDeviceIdButton.leadingAnchor.constraint(equalTo: newDeviceIdTextField.trailingAnchor, constant: 0).isActive = true
}
In this article there is a section which I believe exactly solves my problem. But I just don't understand how.
What am I missing here?
A button automatically sizes its width to fit its content, and both a text field and a button have an automatic height. So what you want to do is trivial:
Pin the left of the text field where you want it.
Pin the right of the button where you want it.
Pin the tops of both where you want them.
Pin the right of the text field to the left of the button and set that constant to a small number such as 8.
You can do this without writing code, from storyboard. What i do for this kind of UI is,
Pin the left of the text field where you want it.
Pin the right of the button where you want it.
Pin the tops of both where you want them.
Pin the right of the text field to the left of the button
It's look like in image below
Now Select button > Size Inspector > In Content hugging Priority
Change Horizontal to 750(high) and you done :)
Result look like in image below

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.

ios draw rectangle with top right corner

I am trying to make a rect which is drawn using it's top right corner (x,y) instead of the usual top left. I tried scaling by -1, but that didn't do the work.
I need it because I am developing an app for RTL locale.
If you use auto layout, you can use the leading and trailing constraints (rather than left and right constraints) and the animation will automatically be adjusted for the target language. For example, consider the following simplistic demo that overlays a "curtain" view, and then, two seconds later "pulls it aside" by animating the trailing constraint:
let curtain = UIView()
curtain.backgroundColor = .darkGrayColor()
curtain.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(curtain)
let trailingConstraint = curtain.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor)
NSLayoutConstraint.activateConstraints([
curtain.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor),
curtain.topAnchor.constraintEqualToAnchor(view.topAnchor),
curtain.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),
trailingConstraint
])
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
trailingConstraint.constant = -self.view.bounds.size.width
UIView.animateWithDuration(0.5) {
self.view.layoutIfNeeded()
}
}
If your project's localization is a LTR language, it will animate the pulling back of this "curtain" from the right edge.
But if you project's localization is a RTL language, such as shown below, then it will animate the pulling of this "curtain" from the left edge:

Resources