I have a UIView containing:
UIButton: (contentMode = Aspect Fit)
UILabel:(numberOfLines = 0, lineBreakMode = byWordWrapping, contentMode = Aspect Fill)
UISwitch: ()
I would like the width and number of lines of the UILabel to adapt to the content of the localized text of UIButton and UILabel.
How should I proceed ?
Behavior expected:
____________________________________________________________________
| | | |
| UIButton | UILabel | UISwitch |
| | | | |
_________________________________v__________________________________
Fred
You will have to give it the required constraints in order to make it fit as you like. You need to provide more details, in order for me to tell you about the constraints you would want. With current information assuming that your button and switch have fixed widths, and are pinned at leading and trailing of superview end respectively. then go through a check of following constraints
(1) give leading constraint of your label equal to trailing constraint of button
(2) give trailing constraint of your label equal to leading constraint of switch
(3) give top and bottom constraint of your button equal to top and bottom constraint of label
(4) give top and bottom constraint of your switch equal to top and bottom constraint of label
Finally, provide a constraint for the y position of your label, and you are good to go.
Another potential solution is using a horizontal stack view, which will save a lot of these constraints.
Here is what I tried... but the size of my button is not as small as possible (I expext it to fit the text)
So, I have added these constraints
NSLayoutConstraint.activate([
resetButton.leadingAnchor.constraint(equalTo: bottomView.leadingAnchor),
resetButton.trailingAnchor.constraint(equalTo: rawLabel.leadingAnchor),
rawLabel.trailingAnchor.constraint(equalTo: directSwitch.leadingAnchor),
directSwitch.trailingAnchor.constraint(equalTo: bottomView.trailingAnchor),
resetButton.topAnchor.constraint(greaterThanOrEqualTo: bottomView.topAnchor),
rawLabel.topAnchor.constraint(equalTo: bottomView.topAnchor),
directSwitch.topAnchor.constraint(greaterThanOrEqualTo: bottomView.topAnchor),
resetButton.bottomAnchor.constraint(lessThanOrEqualTo: bottomView.bottomAnchor),
rawLabel.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor),
directSwitch.bottomAnchor.constraint(lessThanOrEqualTo: bottomView.bottomAnchor),
resetButton.centerYAnchor.constraint(equalTo: bottomView.centerYAnchor),
rawLabel.centerYAnchor.constraint(equalTo: bottomView.centerYAnchor),
directSwitch.centerYAnchor.constraint(equalTo: bottomView.centerYAnchor)
])
and this viewWillAppear func
override func viewWillAppear(_ animated: Bool) {
resetButton.sizeToFit()
rawLabel.numberOfLines = 0
rawLabel.lineBreakMode = .byWordWrapping
rawLabel.preferredMaxLayoutWidth = bottomView.frame.width - resetButton.frame.width - directSwitch.frame.width
}
Related
stackView
+------------+ +
| topView | height: 50 |
+------------+ |
| | |
| | | total height: 300
| bottomView | height: 250 |
| | |
| | |
+------------+ +
I would like to layout two views (topView and bottomView) in a UIStackView (stackView) with these conditions:
stackView has a height (let’s say 300)
topView’s and bottomView’s intrinsic content height is the same (let’s say 50)
topView’s should be rendered with its intrinsic content height (up to stackView’s height) (so 50)
bottomView should take the remaining space (so 250)
if topView’s intrinsic content height changes (let’s say to 100) the distribution should be 100/200
None of the distribution modes of UIStackView can cover this.
Setting a constraint with a constant wouldn’t help here, as the intrinsic content height of topView might change.
So I need some Auto Layout features here. I tried setting different content compression resistance priorities and content hugging priorities. Without success, I still feel like they could be a solution (if I knew how to use them correctly).
It doesn’t seem like a complex problem, I can’t find the right Auto Layout API for this. Any hints?
You should set:
vertical content hugging priority of top view to be more than bottom view
alignment of stack view to fill
distribution of stack view to fill
You should add a width constraint as well, if the top and bottom views do not have intrinsic width.
Demo:
How do I get the 0 width to be equal size with 1 and 2
( . ) to be equal width as 3 and = to be equal width with +?
I can't drag the white square (When clicking the UI button) to resize them.
Screenshot of my storyboard:
Follow Steps
Focus on stack view contain the elements "0 . ="
select ". =" element and embed into a stack view
StackView properties must be "Alignment = Fill", "Distribution = Fill Equally" and "Spacing" as per other elements
Option1
Set the StackView to Distribution Fill and then control drag the 0 Button onto the . Button. Select Equal Widths and then set the Multiplier (times 2 since it should be twice the size) in the Size Inspector.
Option2
Put the .Button and the = Button in an equally filled StackView and then the 0 Button and the StackView in another equally filled StackView. This is probably the better option if it's a 50-50 distribution.
I have a view controller consisting mainly of 2 views.
One that has leading, trailing and bottom anchor aligned with superview and proportional height to superview(0.25), and a scroll view that aligns leading top and trailing to superview/safe area and bottom the other view.
I have a view defined in a xib-file which I create multiple times using Bundle.main.loadNibNamed("VariantResultSlide", owner: self, options: nil)?.first and add them to an array slides. I want to add them to my ScrollView:
for i in 0 ..< slides.count {
scrollView.addSubview(slides[i])
NSLayoutConstraint.activate([
slides[i].leadingAnchor.constraint(equalTo: (i==0) ? scrollView.leadingAnchor : slides[i-1].trailingAnchor),
slides[i].topAnchor.constraint(equalTo: scrollView.topAnchor),
slides[i].bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
slides[i].widthAnchor.constraint(equalTo: scrollView.widthAnchor),
slides[i].heightAnchor.constraint(equalTo: scrollView.heightAnchor)
])
if(i==slides.count-1) {
NSLayoutConstraint.activate([slides[i].trailingAnchor.constraint(equalTo: scrollView.trailingAnchor)])
}
self.updateResultSlides(index: i, vehicle: orderedVehiclesList[i])
}
But then Xcode gives me errors like:
2019-04-11 13:57:07.219263+0200 FleetView[545:190663] [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.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSAutoresizingMaskLayoutConstraint:0x282cecbe0 h=-&- v=-&- FleetView.VariantResultSlide:0x107f214a0.height == UIScrollView:0x102919200.height + 99 (active)>",
"<NSLayoutConstraint:0x282c92300 FleetView.VariantResultSlide:0x107f214a0.height == UIScrollView:0x102919200.height (active)>"
)
and the slides are way too big.
But I can't find any place where I set another constraint for them. Why is this happening?
Your view implements top, bottom and height constraints so obviously its superview will need to resize - but it can't due to constraints created automatically from autoresizing mask. Disable it in you superview with
yourViewsSuperview.translatesAutoresizingMaskIntoConstraints = false
i have a tableviewCell containing 2 labels.
The right one has a fixed width and fixed trailing space to superview and the left one a fixed leading space to superview and trailing to right label.
Sometimes i only need the the left label and in this case i want the left one to have a fixed trailing space to superview instead. So, i created a second inactive constraint and do this in my code:
if(entry.right.isEmpty) {
tableCell?.longConstraint.isActive = true
tableCell?.shortConstraint.isActive = false
tableCell?.rightLabel.isHidden = true
} else {
tableCell?.longConstraint.isActive = false
tableCell?.shortConstraint.isActive = true
tableCell?.rightLabel.isHidden = false
}
but when i load the table all displayed cells have the default constraint active and only after scolling out of view and in again, they are displayed correctly.
For an easy way you can embed them inside a horizontal UIStackview and set
self.rightlb.isHidden = true
and it will disappear with no width automatically , also in your current code make sure
tableCell?.layoutIfNeeded()
after you change the constraints
Try adding this code after adjusting constraints programmatically
tableCell?.setNeedsLayout()
tableCell?.layoutIfNeeded()
Hope this works
I am struggling with adding one button from code to the right corner of the view.
Could someone explain me how can i do this without setting the left constraint ? This would be the left upper V:|-10-[v0], H:|-10-[v0] what would be inversion of it ? I was trying with this : V:[v0]-10-|, H:[v0]-0-| but it does not work like i thought
Thanks in advance!
Based on the comments, I'd like to provide two answers on how to place a UIButton on the top right.
VFL:
Your vertical pin is for the bottom right, not the top. Instead of V:[v0]-10-|, where the "pipe" character (that designates the bounds of the screen) is at the end, place it at the beginning - |-10-[v0].
Provided you've given the button some sort of height/width - which I think you have as the code for "top left" works - this should fix things.
Anchors
Introduced in iOS9, layout anchors (along with layout guides) are a third way to code auto layout. Like NSLayoutConstraints, this is less "visual" than VFL. But unlike NSLayoutConstraints it's less verbose - thus more "Swiftier" IMHO.
To pin a UIButton to the top left, you still need to give auto layout four things - height, width, and X/Y positions. In the following I'm assuming the superview of v0 is called view, like the root view of a UIViewController.
// declare your button
let v0 = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
// remember, you ALWAYS need to turn of the auto resize mask!
v0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v0)
// create a square button
v0.widthAnchor.constraint(equalToConstant: 100.0).isActive = true
v0.heightAnchor.constraint(equalToConstant: 100.0).isActive = true
// pin the button 10 points from the left side of the view
v0.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
// here's how you would pin the button 10 points from the right side of the view
// note the use of a negative here!
// v0.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
// pin the button 10 points from the top of the view
v0.topAnchor.constraint(equalTo: view.topAnchor, constant: 10).isActive = true
}
Like NSLayoutConstraints, layout anchors have constants and multipliers, which you may change if you declare a name for the constraint.
You may combine NSLayoutConstraints with NSLayoutGuides for some nice "adaptive layouts". These guides act like "spacer/invisible" UIViews except for the overhead - they aren't views. You can get a set of Apple "standard" margins (UIView.layoutMarginsGuide), or you can create a set of equally size dynamic guides to space things out equally.
Here's two blogs about layout anchors and layout guides. The examples are written in Swift 2 but there's no syntax changes for Swift 3.