UIStackView without distribution or filling - ios

I have a view on my app where I need to be able to push a dynamic number of custom subviews (the number of views changes whilst its running).
My original idea was a tableview, but it seems a bit OTT setting up all the delegate methods. Then i found UIStackView, which is great as it handles redrawing and resizing when I add and remove the subviews.
However when I have a small number of views in the UIStackView. It will either make each view bigger vertically to fill the space, or distribute them across the stackview depending on the various settings.
What i'd like to have is each view I add just be appended under any existing views in the stack. I don't want distribution or filling of the blank space in the stack. Kind of like a UIStackView with each subview having a height constraint.
I assume this isn't possible with a stackview, so how else can this be achieved? Do I have to use the tableview after all (or fallback to laying it out in code?)

If your views have a defined height constraint, this should work with the Distribution being Equal Spacing.

I managed to do this by setting distribution to fill proportionally and then i pushed at the bottom of the stack a UILabel with some spaces as string. Pushing an empty view or empty UILabel didn't work. I had some constraints errors after this though and didn't investigate further.

Related

UIStackView losing constraints when using custom XIBs

I am attempting to dynamically add views to a UIStackView.
I have a XIB with a full screen UIStackView within. I then have some views - labels and text field/ text views.
The idea here is that I have a class that manages these individual views and that class has it's own XIB file for the layout.
So the class that handles the outermost UIStackView will grab the layout from the individual classes and add it as a subview to the UIStackView.
When attempting to do this, the view appears squashed and not in keeping with the original constraints.
I could offer code but I will explain the constraints.
The outer UIStackView is just stretched as full screen with distribution fill and equal spacing.
An example of an 'inner' view would be a label. I have an individual XIB file that holds a UIView and then a Label within that. The label is pinned to the center of the UIView.
I believe the issue lies with adding custom XIBs to an existing UIStackView. I'm not sure how much more information I give/ is required but I suspect there is something I am missing that someone may spot straight away from the information given.
Any help is appreciated. Thanks.
The UIStackView does exactly what you are asking it to do. If the constraints are setup so the UIStackView fills in the entire screen, then you need to provide content, that when it is equally divided on the screen, has the expected layout, each of the view inserted will be resized to be equally sized.
If you do not know how many views are going to be used, but you need each of your views to take their respective aspect ratio on the screen, then you can use the "Fill Proportionally" option. The UIStackView will add the height of every view, then divide its own height and distribute it proportionally to each view. If you add too many views this too will start to squash your views.
To avoid these kinds of issues, you may wish to put your UIStackView inside of a UIScrollView. You then setup a constraint with very very low priority to set the UIStackView height to 0, as you insert your views the UIStackView will automatically be resized to fit in the different views.
Good luck!

When should we use UIStackView?

I am designing iOS Application since 2 years. I have designed 8-10 applications with using UIScrollView, UICollectionView and many more native views. But I have never used UIStackView. I have gone through many documents of UIStackView, but I am not able to identify exact situation where i can use UIStackView.
Can anyone guide me for same?
Thank you in advance.
UIStackView is useful when you need to repeat same views multiple times like in Sing up view. We use many textfields and manually set constraints between each textfields. But if you put all textfields in stack view then you just need to set required constraints of stackview only and not textfields. Textfields inside stackview will be arranged automatically without Autolayout.
Sometimes we need to hide view and we want to remove its occupied space so at that time use of stackview is recommended because if you hide any view that resided in stackview will also remove its occupied space automatically.
I believe you mean UIStackView. You use a UIStackView to group UI elements together to simplify setting constraints. In other words once you've added objects to the stack view, you constrain the stackview and set attributes on it rather than on each individual element. This results in far fewer constraints.
In this example, I've added a label and a text field to a stack view. Then I added constraints to the stack view and set the spacing in Attributes Inspector to 20.
If I had to constrain the label and the text field I'd have many more constraints.
UIStackView helps you to set autolayout. It isn't neccessary!

How do I prepare a UIViewController's view for being added to a UIStackView?

This is what I'm trying to do...
I have one view controller that needs to dynamically display different subviews based on the presence of some data.
Here is a simple mockup. Each colored block represents a unique subview.
Sometimes the green block needs to be at the top, sometimes the green block won't display at all, sometimes the light blue block will be something different, etc.
Each subview has interactive elements, so I've been creating and adding them like so:
Defining a new view controller
Defining its view
Calling addChildViewController and didMoveToParentViewController
Calling addSubview on myNewViewController.view
Using SnapKit to make auto layout constraints to position the view
I want to transition to UIStackView because it seems a good support system for this view because all I need to do is stack its subviews. I'm seeing many conflicting constraint errors and unexpected view frames when trying to add subviews with their own inner auto layout constraints.
Question
Am I setting myself up for failure here by embedding the views of 4-6 view controllers in the view of one view controller?
Also, how do I give the added views properties like minimum heights or content sizes without seeing many breaking constraints with UIStackView? (So they can stack, but one of them is say, 400 tall, and the other is 200 tall)
Answer
You can absolutely do this using UIContainerViews combined with UIStackViews and UIScrollViews, it's a complicated setup so here's a starter project to get you started:
https://github.com/Rnorback/ScrollingStackView
Here's what that project looks like:
You want the containers to have different sizes. In order to do that, simply add height constraints to the containers with Autolayout. If you want to change the height of the scrolling. Then you'll need to change the height constraint of the UIStackView.
Brief Explanation
When creating this setup, you have to make sure the UIStackView distribution setting stays in fill. That way you can set height constraints on UIContainerViews.
When setting up anything in a UIScrollView you have to make sure that the object is pinned to the edges of the scroll view and has a defined width and height, otherwise the scrollview will throw a constriant error. I think of it like the scrollview tries to press in on all sides of your content view and if any side gives, the scrollview won't be able to present it properly.
Hope this helps.

Constraints in ios

I am learning constraints and spent whole day applying them to the following screen.It is not getting displayed properly in landscape mode.Basically i am not getting how to fix vertical space between ,say, label-Welcome to BBBB and textfield-username so that textfield always appears below the label yet the spacing between them is adjusted according to the screens of different size. If i go for Pin\Vertical space, it automatically fixes the constant value.
Remove the label (or just move it out of the way).
Fill the space that you want to resize with a view.
Constrain this view to the objects above and below and to the sides of the parent view.
Put your label into this view and constrain it to the top of this view and centred to it.
You may need to change the constraints on the objects above and below it to stop them from changing height in an unwanted manner.
This new view should now resize as the device changes orientation but the label should remain at the top of it.
Repeat on other areas of your layout (i.e put things that are not moving around as you want them into sub views and constrain these views to resize accordingly). Experiment with using variable heights, fixed heigh constraints and 'equal heights with' constraints on the views that you add to get them to resize as you need.
Edit: but you have a lot of vertically stacked items in that view - you may never get them all to fit into a horizontal orientation. You may need to remove a few, or add a scroll view or force that view only to layout in portrait mode or... Don't forget to check that it works on all devices you are targeting.
#Ali Beadle was right. Since i had a lot of vertically stacked items, lining them up in landscape mode was not possible. So, i went for scrollview.
I have taken a ScrollView first and then a UIView named ContentView on that ScrollView. I have made the width of ContentView equal to the width of parent UIView and kept its height fixed to 568. In my code i set
_contentViewHeight.constant = self.view.frame.size.height;
Now it scrolls in landscape mode while in potrait mode, it does'nt scroll.
I run into Autolayout problems all the time. But I finally figured out a way to overcome a lot of issues that arise from it.
I simply will use a container-View like ScrollView or even a plain old UIView, place all my controls in it. thats it. this makes things a lot easier for autolayout to figure out the constraints. in your case you could just use a UIView.
-start off by removing all the constraints you have I would start by selecting each control in the XIB and see if it has width/height constraint, select it then press the delete key then at the bottom of the project explorer you'll see all the constraints that auto layout has select each one then delete. that should get rid of any complaints that auto-layout might have.
-Place a UIView object inside your main View then
-move all the controls inside it. Then
-add the necessary constraints for the container view so it'll resize in different orientations and don't worry about any constraints inside the container view (auto layout will figure them out automatically).
that does the trick for me usually.

Simple scroll view constraints change?

I created a scroll view in Xcode that works awesome because of this video.
https://www.youtube.com/watch?v=3PIm8-lKAYw
When I was messing around after I made it I found out that if I clicked on the scroll view and went to Show the Size Inspector or the fifth button on the right hand side of the screen I had the option to make a constraint called Top Space change in value that caused the scroll view to become bigger and smaller. I decided to see if I could find a way to change the constraint programmatically by simply using dot notation and the equaling it to an int value that I wanted.
So what I'm trying to figure out is there a simple way to change these constraints values programmatically that change the scroll view constraints values?
Without actually following that tutorial (and there being no code in your question) I'm going to make a few assumptions.
Yes, it is possible to change the scroll view's content size by manipulating constraints in your code. If you are creating the constraints in a xib or storyboard, you will need to make sure they are hooked up to IBOutlets so that you can access them in your code.
If you have 2 views arranged vertically that affect the vertical content size of your scroll view, increasing the space between these views would also increase the vertical size of your scrollview's content size. The following would increase the space between 2 views by 20 (assuming a multiplier of 1) and subsequently increase the scrollview's vertical space by the same amount.
// This is a vertical space constraint created in your xib or storyboard between 2 views that drive the content size of your scrollview
someVerticalSpaceConstraint.constant += 20;

Resources