Constraints for progress bar and label together in IOS Swift - ios

I need to show a progress bar and a label adjacent to each other horizontally based on some condition and based on a different condition, I need to show label and progress bar one below the other vertically. Third condition is I hide the label and show only the progress bar. For the third condition, I want the progress bar to occupy the full width of the screen - some space on either end of it. Initially, I started by putting constraints to show them side by side and it worked. However, for the other two conditions when I try to modify existing constraints during run time, it is messing up and not working as expected. Any pointers on how the constraints should look like for these scenarios. Attached is an image of a progress bar and label side by side

Add a horizontal UIStackview and add a UIProgressView and a UILabel. Set label text alignment to center.
Add top, bottom, leading, trailing constraints to the stackview. Don't add height constraint to the stackview. Add height constraint to the label.
Change stackview configuration as
And change the styles by changing stackview's axis and hiding/showing the label as follows
#IBAction func style1(_ sender: Any) {
stackView.axis = .horizontal
stackView.alignment = .center
label.isHidden = false
}
#IBAction func style2(_ sender: Any) {
stackView.axis = .vertical
stackView.alignment = .fill
label.isHidden = false
}
#IBAction func style3(_ sender: Any) {
stackView.axis = .horizontal
stackView.alignment = .center
label.isHidden = true
}

I need to show a progress bar and a label adjacent to each other horizontally based on some condition and based on a different condition
For this purpose
Progress bar constraints
Label Constraints
I need show label and progress bar one below the other vertically
For this purpose
Progress bar constraints
Label Constraints
Third condition is I hide the label and show only the progress bar. For the third condition, I want the progress bar to occupy full width of the screen - some space on either ends of it
This one is bit tricky but not much difficult, Set constraints according to our first problem, and add one extra constraint along with others, Trailing Space to superview, Stroyboard will show you error, don't worry. Create an outlet for Progressbar trailing space both constraints now in your Swift/objc file and on runtime activate one constraint and deactivate other according to your logic. Along with showing/hiding your label. Like this
NSLayoutConstraint.isActive = false; // or true. Here NSLayoutConstraint is your reference to constraint outlet.

Related

Force UIView with zero height to lay out its subviews

I have an UIView with some labels in it. The labels have dynamic height depending on the text, and they have vertical spacing constraints to the parent view and to each other, giving the parent view its height. The constraint between the bottom of the last label and the bottom of the parent view is set to have a lower priority.
Additionally, the parent view has a height constraint that I set to 0 in viewDidLoad. This collapses the view and pushes all the labels down, since the last bottom constraint has a lower priority. I then have a button where I toggle the height constraint of the parent view, which opens/closes it:
#IBAction func viewInfoButtonTapped(_ sender: Any) {
viewInfoButton.isSelected = !viewInfoButton.isSelected
self.infoHeightConstraint.isActive = !self.viewInfoButton.isSelected
UIView.animate(withDuration: 0.25) {
self.view.layoutIfNeeded()
}
}
My issue is that the dynamic height of the labels are not set until I expand the parent view the first time, so instead of an animation where the labels are simply revealed, I get an effect where thy are revealed and grow in height at the same time. After the first expansion, the heights have been set, and subsequent expansions give the correct effect.
How can I force the view to lay out the constraints correctly before it is expanded the first time?
I have tried calling setNeedsLayout() and layoutIfNeeded(), but it doesn't seem to have an effect.
Set the Vertical Content Compression Resistance priority to Required (1000) on each of your labels:
Or, since you're likely looping through them at run-time to set the text in each, you can do it via code:
label.text = someString
label.setContentCompressionResistancePriority(.required, for: .vertical)
That should fix the initial "stretching" that you don't want.
If you're still seeing stretching (shouldn't, but just in case) you can also call sizeToFit():
label.text = someString
label.setContentCompressionResistancePriority(.required, for: .vertical)
label.sizeToFit()

How to center image in StackView conditionally

I have a StackView containing a UIImageView and a UILabel. Sometimes the UILabel contains a quotation and sometimes it does not. When it does I want the UIImageView to be 40% of the device width - I have that part working. When it does not I want the UIImageView still to be the same width, just centered horizontally. What's the easiest way to achieve this?
It seems that UIStackView is not what you really need there, but rather simple UIView, which is centered vertically in the parent view, and contains UIImageView and UILabel, and then set imageView.trailing equal to label.leading, plus label.sizeToFit().
But if you want to stick to your design, what you could do is programmatically set UIStackView axes. For instance, set stack view in IB like:
UIStackView IB setting
and then in code in viewDidLoad() method:
if label.text == "" {
stackView.axis = .vertical
} else {
stackView.axis = .horizontal
}
also with label.sizeToFit().
That should do the trick.

UIStackview not resizing when hiding the labels inside it

Hi I'm new to UIStackViews.
So I have a vertical Stackview containing 8 Labels.
However, the problem with my Stackview is that whenever I hide the Labels inside it, my stackview does not resize.
The labels within the Red Rectangle are in my Stackview
When I hide those labels of the Stackview, I want my screen to look like this
However for some reason when I hide those labels, it looks like this instead with all the space visible and the stuff at the bottom doesn't go up
How do I fix this?
Here's how I hid the labels:
override func viewDidLoad() {
super.viewDidLoad()
showingResultLabel.isHidden = true
addressLabel.isHidden = true
costOfKitLabel.isHidden = true
costOfModularLabel.isHidden = true
dispatchedFromLabel.isHidden = true
kitHomecostLabel.isHidden = true
modularHomecostLabel.isHidden = true
dispatchFromLabel.isHidden = true
Thanks
Just hide the labels works. You need to set constraints to make it work. I upload images of constraints.
stackview's constraint
hiding a label inside stack view does not effect the height.
I suggest that, when you want to show some detail (stackView contain some UILabel),
create the UILabel e.g:
let label = UILabel()
label.textColor = .black
label.text = ""
label.backgroundColor = .clear
then add the UILabelView to the stack view
stackViewName.addArrangedSubview(label)
at the end, instead of hide a label inside stack view, you have to remove the UILabel from the stack view
stackView.removeArrangedSubview(label)
so i think this will effect the hight of your stackView .

UIButton size not updating automatically after updating button image, using autolayout

I have a UIButton which is constrained with leading, trailing and center vertically constraints. The label on the left of the button grows until the trailing constraint of the button (greater than constraint) reaches the limit at which point the button does not move any closer to the switch and the label text begins to truncate.
There is a case where the button is set to hidden. This creates an extra gap between the label and switch when there is long text in the label. I am setting the image of the button to nil and expect it to resize based on the constraints but it never does.
Here is the code that attempts to force the resizing:
func hideInfoButon(hide: Bool) {
infoButton.hidden = hide
if hide {
infoButton.setImage(nil, forState: .Normal)
} else {
infoButton.setImage(UIImage(named: "icn_info_gry"), forState: .Normal)
}
setNeedsUpdateConstraints()
setNeedsLayout()
}
I have confirmed that the hide method is properly called and the image is actually being set to nil. I confirmed by not hiding the button and giving it a background color to make it visible.
Is there a solution which does not require me to add a width constraint to the button?
The content is in a tableViewCell for reference.
1. Add Constraints to label
2. Add Constraints to Info Button
3. Info Button trailing space must be standard spacing
4. Create Info Button Width IBOutlet Like
5. And when you wnat to hide button set width constraints 0
infoButtonWidth.constant=0
A hidden button will still occupy space. You could alternatively remove the button rather than hiding it...
infoButton.removeFromSuperview()
If you do this, you will probably also need an extra constraint between the label and the switch for when the button is removed. This constraint should have a lower priority so that it does not conflict when the button is visible.
EDIT:
Thinking about it further, this may cause headaches when cells are reused between rows. You may find it easier to have an IBOutlet for the button's width constraint, and just set it to zero to hide.

Is it possible for UIStackView to scroll?

Let's say I have added more views in UIStackView which can be displayed, how I can make the UIStackView scroll?
In case anyone is looking for a solution without code, I created an example to do this completely in the storyboard, using Auto Layout.
You can get it from github.
Basically, to recreate the example (for vertical scrolling):
Create a UIScrollView, and set its constraints.
Add a UIStackView to the UIScrollView
Set the constraints: Leading, Trailing, Top & Bottom should be equal to the ones from UIScrollView
Set up an equal Width constraint between the UIStackView and UIScrollView.
Set Axis = Vertical, Alignment = Fill, Distribution = Equal Spacing, and Spacing = 0 on the UIStackView
Add a number of UIViews to the UIStackView
Run
Exchange Width for Height in step 4, and set Axis = Horizontal in step 5, to get a horizontal UIStackView.
I present you the right solution
For Xcode 11+
Step 1:
Add a ScrollView and resize it
Step 2:
Add Constraints for a ScrollView
Step 3:
Add a StackView into ScrollView, and resize it.
Step 4:
Add Constraints for a StackView (Stask View -> Content Layout Guide -> "Leading, Top, Trailing, Bottom")
Step 4.1:
Correct Constraints -> Constant (... -> Constant = 0)
Step 5:
Add Constraints for a StackView (Stask View -> Frame Layout Guide -> "Equal Widths")
Step 6 Example:
Add two UIView(s) with HeightConstraints and RUN
I hope it will be useful for you like
Apple's Auto Layout Guide includes an entire section on Working with Scroll Views. Some relevant snippets:
Pin the content view’s top, bottom, leading, and trailing edges to the scroll view’s corresponding edges. The content view now defines
the scroll view’s content area.
(Optional) To disable horizontal scrolling, set the content view’s width equal to the scroll view’s width. The content view now fills the
scroll view horizontally.
(Optional) To disable vertical scrolling, set the content view’s height equal to the scroll view’s height. The content view now fills
the scroll view horizontally.
Furthermore:
Your layout must fully define the size of the content view (except
where defined in steps 5 and 6). … When the content view is taller than the scroll view, the scroll view enables vertical scrolling. When the content view is wider than the scroll view, the scroll view enables horizontal scrolling.
To summarize, the scroll view's content view (in this case, a stack view) must be pinned to its edges and have its width and/or height otherwise constrained. That means that the contents of the stack view must be constrained (directly or indirectly) in the direction(s) in which scrolling is desired, which might mean adding a height constraint to each view inside a vertically scrolling stack view, for example. The following is an example of how to allow for vertical scrolling of a scroll view containing a stack view:
// Pin the edges of the stack view to the edges of the scroll view that contains it
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
// Set the width of the stack view to the width of the scroll view for vertical scrolling
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
Up to date for 2020.
100% storyboard OR 100% code.
This example is vertical:
Here's the simplest possible explanation:
Have a blank full-screen scene
Add a scroll view. Control-drag from the scroll view to the base view, add left-right-top-bottom, all zero.
Add a stack view in the scroll view. Control-drag from the stack view to the scroll view, add left-right-top-bottom, all zero.
Put two or three labels inside the stack view.
For clarity, make the background color of the label red. Set the label height to 100.
Now set the width of each UILabel:
Surprisingly, control-drag from the UILabel to the scroll view, not to the stack view, and select equal widths.
To repeat:
Don't control drag from the UILabel to the UILabel's parent - go to the grandparent. (In other words, go all the way to the scroll view, do not go to the stack view.)
It's that simple. That's the secret.
Secret tip - Apple bug:
It will not work with only one item! Add a few labels to make the demo work.
You're done.
Tip: You must add a height to every new item. Every item in any scrolling stack view must have either an intrinsic size (such as a label) or add an explicit height constraint.
The alternative approach:
To recap the above approach: surprisingly, set the widths of the labels to the width of the scroll view (not the stack view).
Here is an alternate approach...
Drag from the stack view to the scroll view, and add a "width equal" constraint. This seems strange because you already pinned left-right, but that is how you do it. No matter how strange it seems that's the secret.
So you have two options:
Surprisingly, set the width of each item in the stack view to the width of the scrollview grandparent (not the stackview parent).
or
Surprisingly, set a "width equal" of the stackview to the scrollview - even though you do have the left and right edges of the stackview pinned to the scrollview anyway.
To be clear, do ONE of those methods, do NOT do both.
The constraints in the top-voted answer here worked for me, and I've pasted an image of the constraints below, as created in my storyboard.
I did hit two issues though that others should be aware of:
After adding constraints similar to those in in the accepted answer, I'd get the red autolayout error Need constraints for: X position or width. This was solved by adding a UILabel as a subview of the stack view.
I'm adding the subviews programmatically, so I originally had no subviews on the storyboard. To get rid of the autolayout errors, add a subview to the storyboard, then remove it on load before adding your real subviews and constraints.
I originally attempted to add UIButtons to the UIStackView. The buttons and views would load, but the scroll view would not scroll. This was solved by adding UILabels to the Stack View instead of buttons. Using the same constraints, this view hierarchy with the UILabels scrolls but the UIButtons does not.
I'm confused by this issue, as the UIButtons do seem to have an IntrinsicContentSize (used by the Stack View). If anyone knows why the buttons don't work, I'd love to know why.
Here is my view hierarchy and constraints, for reference:
As Eik says, UIStackView and UIScrollView play together nicely, see here.
The key is that the UIStackView handles the variable height/width for different contents and the UIScrollView then does its job well of scrolling/bouncing that content:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
Horizontal Scrolling (UIStackView within UIScrollView)
For horizontal scrolling. First, create a UIStackView and a UIScrollView and add them to your view in the following way:
let scrollView = UIScrollView()
let stackView = UIStackView()
scrollView.addSubview(stackView)
view.addSubview(scrollView)
Remembering to set the translatesAutoresizingMaskIntoConstraints to false on the UIStackView and the UIScrollView:
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
To get everything working the trailing, leading, top and bottom anchors of the UIStackView should be equal to the UIScrollView anchors:
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
But the width anchor of the UIStackView must the equal to or greater than the width of the UIScrollView anchor:
stackView.widthAnchor.constraint(greaterThanOrEqualTo: scrollView.widthAnchor).isActive = true
Now anchor your UIScrollView, for example:
scrollView.heightAnchor.constraint(equalToConstant: 80).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo:view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo:view.trailingAnchor).isActive = true
Next, I would suggest trying the following settings for the UIStackView alignment and distribution:
topicStackView.axis = .horizontal
topicStackView.distribution = .equalCentering
topicStackView.alignment = .center
topicStackView.spacing = 10
Finally you'll need to use the addArrangedSubview: method to add subviews to your UIStackView.
Text Insets
One additional feature that you might find useful is that because the UIStackView is held within a UIScrollView you now have access to text insets to make things look a bit prettier.
let inset:CGFloat = 20
scrollView.contentInset.left = inset
scrollView.contentInset.right = inset
// remember if you're using insets then reduce the width of your stack view to match
stackView.widthAnchor.constraint(greaterThanOrEqualTo: topicScrollView.widthAnchor, constant: -inset*2).isActive = true
I was looking to do the same thing and stumbled upon this excellent post. If you want to do this programmatically using the anchor API, this is the way to go.
To summarise, embed your UIStackView in your UIScrollView, and set the anchor constraints of the UIStackView to match those of the UIScrollView:
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
Just add this to viewdidload:
let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollVIew.contentInset = insets
scrollVIew.scrollIndicatorInsets = insets
source:
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/LayoutUsingStackViews.html
You can try ScrollableStackView : https://github.com/gurhub/ScrollableStackView
It's Objective-C and Swift compatible library. It's available through CocoaPods.
Sample Code (Swift)
import ScrollableStackView
var scrollable = ScrollableStackView(frame: view.frame)
view.addSubview(scrollable)
// add your views with
let rectangle = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 55))
rectangle.backgroundColor = UIColor.blue
scrollable.stackView.addArrangedSubview(rectangle)
// ...
Sample Code (Objective-C)
#import ScrollableStackView
ScrollableStackView *scrollable = [[ScrollableStackView alloc] initWithFrame:self.view.frame];
scrollable.stackView.distribution = UIStackViewDistributionFillProportionally;
scrollable.stackView.alignment = UIStackViewAlignmentCenter;
scrollable.stackView.axis = UILayoutConstraintAxisVertical;
[self.view addSubview:scrollable];
UIView *rectangle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 55)];
[rectangle setBackgroundColor:[UIColor blueColor]];
// add your views with
[scrollable.stackView addArrangedSubview:rectangle];
// ...
Adding some new perspective for macOS Catalyst. Since macOS apps support window resizing, it is possible that your UIStackView will transition from an unscrollable status to a scrollable one, or vice versa. There are two subtle things here:
UIStackView is designed to fit all area it can.
During the transition, UIScrollView will attempt to resize its bounds to account for the newly gained/lost area underneath your navigation bar (or toolbar in the case of macOS apps).
This will unfortunately create an infinite loop. I am not extremely familiar with UIScrollView and its adjustedContentInset, but from my log in its layoutSubviews method, I am seeing the following behavior:
One enlarges the window.
UIScrollView attempts to shrink its bounds (since no need for the area underneath the toolbar).
UIStackView follows.
Somehow UIScrollView is unsatisfied, and decide to restore to the larger bounds. This feels very odd to me since what I am seeing from the log is that UIScrollView.bounds.height == UIStackView.bounds.height.
UIStackView follows.
Then loop to step 2.
It appears to me that two steps would fix the issue:
Align UIStackView.top to UIScrollView.topMargin.
Set contentInsetAdjustmentBehavior to .never.
Here I am concerned with a vertically scrollable view with a vertically growing UIStackView. For a horizontal pair, change the code accordingly.
Hope it helps anyone in the future. Couldn't find anyone mentioning this on the Internet and it costed me quite a long time to figure out what happened.
If any one looking for horizontally scrollview
func createHorizontalStackViewsWithScroll() {
self.view.addSubview(stackScrollView)
stackScrollView.translatesAutoresizingMaskIntoConstraints = false
stackScrollView.heightAnchor.constraint(equalToConstant: 85).isActive = true
stackScrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
stackScrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
stackScrollView.bottomAnchor.constraint(equalTo: visualEffectViews.topAnchor).isActive = true
stackScrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.topAnchor.constraint(equalTo: stackScrollView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: stackScrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: stackScrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: stackScrollView.bottomAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: stackScrollView.heightAnchor).isActive = true
stackView.distribution = .equalSpacing
stackView.spacing = 5
stackView.axis = .horizontal
stackView.alignment = .fill
for i in 0 ..< images.count {
let photoView = UIButton.init(frame: CGRect(x: 0, y: 0, width: 85, height: 85))
// set button image
photoView.translatesAutoresizingMaskIntoConstraints = false
photoView.heightAnchor.constraint(equalToConstant: photoView.frame.height).isActive = true
photoView.widthAnchor.constraint(equalToConstant: photoView.frame.width).isActive = true
stackView.addArrangedSubview(photoView)
}
stackView.setNeedsLayout()
}
One simple way for dynamic elements in stackview embed in scrollview. In XIB, add a UIStackView inside an UIScrollView and add constraints that the stackview fit the scrollview (top, bottom, lead, trail) and add a constraint to match horizontal center between them. But marked "remove at build time" the last constraint. It make XIB happy and avoid errors.
Example for horizontal scroll:
Then:
Then in your code, just add elements like buttons in your stackview like this:
array.forEach { text in
let button = ShadowButton(frame: .zero)
button.setTitle(text, for: .normal)
myStackView.addArrangedSubview(button)
button.heightAnchor.constraint(equalToConstant: 40).isActive = true
button.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
If you have a constraint to center the Stack View vertically inside the scroll view, just remove it.
Example for a vertical stackview/scrollview (using the EasyPeasy for autolayout):
let scrollView = UIScrollView()
self.view.addSubview(scrollView)
scrollView <- [
Edges(),
Width().like(self.view)
]
let stackView = UIStackView(arrangedSubviews: yourSubviews)
stackView.axis = .vertical
stackView.distribution = .fill
stackView.spacing = 10
scrollView.addSubview(stackView)
stackView <- [
Edges(),
Width().like(self.view)
]
Just make sure that each of your subview's height is defined!
First and foremost design your view, preferably in something like Sketch or get an
idea of what do you want as a scrollable content.
After this make the view controller free form (choose from attribute
inspector) and set height and width as per the intrinsic content
size of your view (to be chosen from the size inspector).
After this in the view controller put a scroll view and this is a
logic, which I have found to be working almost all the times in iOS (it may require going through the documentation of that view class which one can obtain via command + click on that class or via googling)
If you are working with two or more views then first start with a view, which has been introduced earlier or is more primitive and then go to the view which has been introduced
later or is more modern. So here since scroll view has been
introduced first, start with the scroll view first and then go to the
stack view. Here put scroll view constraints to zero in all direction vis-a-vis its super view. Put all your views inside this scroll view and then put them in stack view.
While working with stack view
First start with grounds up(bottoms up approach), ie., if you have labels, text fields and images in your view, then lay out these views first (inside the scroll view) and after that put them in the stack view.
After that tweak the property of stack view. If desired view is still not achieved, then use another stack view.
If still not achieved then play with compression resistance or content hugging priority.
After this add constraints to the stack view.
Also think of using an empty UIView as filler view, if all of the above is not giving satisfactory results.
After making your view, put a constraint between the mother stack view and the scroll view, while constraint children stack view with the mother stack view.
Hopefully by this time it should work fine or you may get a warning from Xcode giving suggestions, read what it says and implement those. Hopefully now you should have a working view as per your expectations:).
For nested or single Stack view scroll view must be set a fixed width with the root view. Main stack view which is inside of scroll view must set the same width. [My scroll view is bellow of a View ignore it]
Set up an equal Width constraint between the UIStackView and
UIScrollView.
Place a scroll view on your scene, and size it so that it fills the scene. Then, place a stack view inside the scroll view, and place the add item button inside the stack view. As soon as everything’s in place, set the following constraints:
Scroll View.Leading = Superview.LeadingMargin
Scroll View.Trailing = Superview.TrailingMargin
Scroll View.Top = Superview.TopMargin
Bottom Layout Guide.Top = Scroll View.Bottom + 20.0
Stack View.Leading = Scroll View.Leading
Stack View.Trailing = Scroll View.Trailing
Stack View.Top = Scroll View.Top
Stack View.Bottom = Scroll View.Bottom
Stack View.Width = Scroll View.Width
code:Stack View.Width = Scroll View.Width is the key.
In my case the number of views inside the stackView was variable and I wanted to center the items. So, for instance, with one view in the stackView, I wanted this view to be centered in the middle of the screen, and if all the views did not fit inside the screen, I wanted the view to be scrollable.
This is the hierarchy of my view.
So I set a fixed width for the button, then, for the stackView:
Same fixed width as the button but with 650 priority.
Align X center to containerView
Trailing >= 0 and leading >= 0 to containerView
Bottom and top space to containerView
For the containerView:
Trailing, leading, bottom, top, equal height, equal width (250 priority) to superview
Fixed height
For the scrollView:
Trailing, leading, bottom, top to superview
The scrollView is also embedded in a view that has leading and trailing constraints.
And about the code I used to approach this:
for index in 0...array.count - 1 {
if index == 0 {
firstButton.setTitle(title, for: .normal)
} else {
let button = UIButton()
button.setTitle(title, for: .normal)
stackView.addArrangedSubview(button)
stackView.setNeedsLayout()
}
}
containerView.layoutIfNeeded()
stackView.distribution = .fillEqually
stackView.spacing = 10
stackView.alignment = .fill
something everyone seems to have missed when doing this with Storyboard is FIX THE MULTIPLIER!
When you're following the steps above in anyones tutorial and resetting the constant to 0 also check the multiplier and reset it to 1, it will have taken on some other factor when visually linking to remain in place
I found I can make a LOOOOOOOOOOOONG text block squash or stretch in a UIStackView simply with
Simply
Add constraints to the scrollview
Top left bottom right, cons 0
Add constraints to the stack view pointing at the scrollbars Content Layout Guide
Then add equal width or equal height constraint from the Frame Layout Guide.
Pick : width if the content needs to scroll vertically, height if it needs to scroll horizontally.
Now here is the key. Edit each constraint and reset the constant to 0 AND set the multiplier back to 1!!!!!
It gets wonky if you don't
If it works you can click on the inner content and mouse scroll

Resources