Reverse scrollview height controlled by stack view in storyboard - ios

My Goal
To make a reverse scroll view that changes height with the height of the vertical stack (the contents of which will be controlled programatically)
What I have tried
Setting the stack view, Scroll view and content view the same heights. I am not sure how to change the simulated size of the view controller with it
Note: I am using Storyboard not swift UI, I have researched this and all I can find are tutorials for how to do this in SwiftUI
I wanted it to be controlled by the height of the stack view, so it does not scroll when there isn't anything to scroll to, if this is wrong please correct me and give me some guidance
The ViewController now:
Can anyone help?

If I understand your question correctly, I had a similar issue recently.
My solution was:
Fully constrain the UIScrollview within the superview
Place a UIView inside the UIScrollView. Align the UIView's leading and trailing constraints to the UIScrollView's content layout guide AND frame layout guide ( =0, or whatever margin you need). Align the UIView's top and bottom constraints to the UIScrollView's content layout guide ( =0 ). Constrain the UIView's height to be equal to the height of the UIScrollView's frame layout guide with a priority of 500 (make sure the multiplier is 1 as Autolayout might set it to something else). These constraints should be added by control dragging from the UIView to the UIScrollView's layout guides within the document outline (I had problems if I didn't add them this way). This fixes the widths, but if the UIView's height needs to expand then the equal height constraint can break allowing it to grow outside the UIScrollView's frame, triggering scrolling.
Place your UIStackView inside the UIView. Align the UIStackView leading and trailing constraints to the superview (the UIView), or use a horizontally centred within superview constraint. Constrain the UIStackView to be vertically centred within the superview (again, the UIView). Align the bottom constraint of the UIStackView to be >=0 relative to the superview (UIView). Thus, when the UIStackView is smaller than the UIView (and UIScrollView) it remains centred and doesn't scroll. As soon as the UIStackView (and UIView) exceeds the size of the UIScrollView, the >=0 constraint between UIStackView and UIView bottom takes precedence over the equal height constraint between the UIView and UIScrollView frame layout guide, forcing scrolling.
In step 3, I think you might be better served by aligning the top of the UIStackView to the top of the UIView, rather than having the UIStackView vertically centred. The bottom constraint should still be >=0. I didn't try this myself but it should still work.
If you need the UIScrollView itself to increase in size, then pin its top and bottom within the superview to the minimum size you want it to be, with a low priority such as 250, then add >= constraints to fix the outer limit of where you want it to be. For example, Constrain the bottom of the UIScrollView to be =100 from the bottom safe area guide with a priority of 250, then constrain it to also be >= 25 from the bottom safe area with the default priority of 1000. In this case the first constraint to break should be the bottom of the UIScrollView which will allow the UIScrollView to grow until it hits the bottom >=25 constraint, at which point the UIView to UIScrollView_frame_layout_guide equal height constraint will break triggering scrolling.
I hope that makes sense (and that I haven't missed anything)!
PS I also ran into a problem with the UIStackView contents (programatically defined in my case) resizing in odd ways which seemed to be fixed by changing content mode from "Scale to Fill" to "Redraw". I set distribution to "Fill Equally" or "Fill Proportionally" depending on the look I wanted (I had two such views).

Related

UIScrollView - Need Constraints for x position/width, Need Constraints for y position/height

I have a view hierarchy that looks like this (based on other answers and Apple's advanced AutoLayout guide for working with UIScrollView):
The 2 steps required for ScrollView are:
Set up constraints for position and size (frame) of ScrollView: The same way you do it with any other view.
Set up constraints for content size: By making sure that there are constraints from the ScrollView's subviews touching all edges (leading, trailing, top, bottom) of the ScrollView, if you're doing this in interface builder and not programmatically.
Step 1 worked fine at first and this was the result:
No problems with position and size as expected. I just need to define the content size (content height and content width) now in Interface Builder with Step 2.
Now I add the constraints touching all 4 edges of the ScrollView like so:
Suddenly, the ScrollView doesn't know it's position and size (frame) anymore.
I've looked at other answers and followed the various steps, but can't seem to resolve this issue. Sorry I'm not able to post Storyboard screenshots because of privacy issues
Set the scroll view's top, bottom, leading, trailing constraints to its superview to 0.
Set the view that is inside the scroll view and set its top, bottom, leading, trailing constraints to its superview to 0.
Select the view that is inside the scroll view, go to the size inspector and set the "Intrinsic size" to "Placeholder".
Scroll views can be a little tricky at first. You really have 3 parts:
Actual frame of the scroll view
Actual frame of the subview(s) contained in the scroll view
The contentSize of the scroll view - that is, how far it should scroll in either direction
So, 1. is pretty straight-forward.
The second part also seems straight-forward, except that we tend to "pin" subviews to the inside edges of their superviews. In the case of scroll view subviews, those constraints are what defines the contentSize. You also have to make sure the subviews have a "size".
Starting with just one subview, you would:
set the scroll view's constraints as "normal".
set the size of the subview - just for demo purposes, set it to 100 x 100
pin all four edges of the subview to the four edges of the scroll view
Run the app. Assuming you set background colors so you know what you're looking at, you should see the scroll view positioned and sized as you'd expect... you should see the subview of 100 x 100 sitting somewhere inside the scroll view... and you will likely not be able to do any actual scrolling.
If you go back and change the subview to, say, 100 x 800, and still have its bottom constraint pinned to the bottom of the scroll view (the subview's superview), and run the app again... You should be able to scroll up and down for the full 800 pt height of the subview.
The way to think about it is: the scroll view's content - whether it's one or many subviews - has to define its own size, which will define the scrollable area (the scroll view's contentSize).
Hope that makes sense!

UIScrollView height while adding content programmatically in UIStackView

I am trying to make a view containing an UIScrollView. This UIScrollView contains 3 UIViews. The last one contains another UIStackView I wanted to fill at runtime.
Here an image of the storyboard :
But when I add content at runtime in the second UIStackView, the ScrollView's height remains the same.
The second UIStackView is defined as the first one with:
Axis : vertical
Alignment : Fill
Distribution : Equal Spacing
Then I use :
mStackView.addArrangedSubview(matProgress)
The result below :
What's the way to have the bottom view and the ScrollView stretch to fit the content.
The layout can be done with auto-layout and constraints.
The key points are:
do not set height constraints on either StackView
set the "Main" StackView Distribution to Equal Spacing
set the "Main" StackView Leading, Trailing, Top and Bottom constraints to its Superview (which is the ScrollView)
you do need to also set a width constraint on the "Main" StackView to control the horizontal contentSize
The only quirk will be on startup. If you have NO content in the bottom / inner StackView, it will still "exist" in the Main StackView and take up space. There is a trick to get around that, but it must be done in code.
You can see a working example here: https://github.com/DonMag/StackyScrolly
If you have UIScrollView and the child views with auto-layout. Setting programmatically the height of the scrollview will stretch the inside views to comply with the auto-layout.
So, you get by code the height of the third view and set the UIScrollView height to view1.height + view2.height + expectedThirdViewHeight.

How do you set constraints for scrollview that doesn't occupy the whole parent view

I'm trying to build UI similar to that of ios photo gallery : Navigation view controller with a scrollview occupying 80% height and 100% width of the parent's view and the collection view controller occupying the rest of the height and 100% width. So here's how it looks like :
The blue area is scrollview and its content view. The bottom part is a collection view which suppose to behave like a carousel. You can see the constraints that I have set in the following screenshot :
:
I want to set the scrollview height so that it only occupies 80% of the parent view estate and the collection view occupies the rest. However, I can't seem to resolve scrollview constraint issues such as autolayout not able to resolve height/y position of scrollview. As you can see in the above pic, I tried setting the height of the scrollview to 50% of the parent view but the autolayout still complains about not being able to resolve height. If I let interface builder resolve the issue, it just adds spacing to the content view inside scrollview and pushes it down as a result. You can see that in the following screenshots.
Your view heirarchy is correctly setup so thats quite nice and you are on the right track of what constraints to add. I'm going to write all the constraints starting from step 1.
To your UIScrollView add a top, leading and trailing constraint to the superView. Also add a equal height constraint between your UIScrollView and the superView and set the multiplier to 0.8.
Now add your UICollectionView below the UIScrollView and give it a leading, trailing and bottom to the superView. Also add a vertical spacing between the UICollectionView and UIScrollView.
Now add for the contentView inside the UIScrollView. Add a leading, top, bottom and trailing for the contentView to UIScrollView. As soon as you do this, the constraints will break and Xcode will complain. Now what you need to do more is add a equal height and width constraint between the UIScrollView and contentView. Set the priority of this equal height constraint (assuming you want vertical scroll) to something like 250, so that it breaks when the content inside the UIScrollView becomes too large to be displayed completely.
Now as far as that extra spacing issue is concerned. What you need to do is, select the UIViewController that has your UIScrollVIew and then select the attributes inspector for this UIViewController and uncheck the adjust scroll view insets option. For a screenshot, check this.
As i see from above do the following.
Add leading, trailing and top constraint to scrollview.
Add height constraint i.e drag from scrollview to superview and add equal width, in equal width constraint change the multiple factor to 0.8.
Add leading trailing, bottom constraint to collection view with respect to superview and vertical space constraint with respect to scrollview.

dynamic height of of scrollview subviews in autolayout ios

I am creating a UIScrollView from xib, in which 3 view are there 2 UIViews and in middle an UIImageView. when I am setting constraints Xcode asked to set Y position constrains. But the problem is Y position constraint is blocking Scrollview to scroll down and automatically adjusting the views which looks ugly in landscape mode.
when I am delete that constraint it ask to fix height of subview. I searched a lot but I am new in autolayout so not understanding many of solutions. any help would be great.
You have to set all the height constraints in the content view.
But you also want the height of the Content to be proportional to the screen size.
To do this assign the height constraint of the imageview [equal|proportional|a-computation-of] to the view containing the UISCrollView.
It seems weird to skip levels of herarchy when assigning constraints between two views whose are not direct ancestor/sibling of each other but within a scrollview (at least) it is perfectly acceptable.
You are basically telling the scrollview that it's content has a known size and at same time setting this content to adapt dinamically to the screen size (if the constraints of the root uiview are set correctly)
UIView1
|---UIScrollView
|---UIView2
|---UIImageView [heightConstr.constant=UIView1.height-UIView2.height-UIView3.height-margins]
|---UIView3
This is the basic idea, to be done programmatically, then you can explore other solutions.
Unfortunately the constraint system in ios pretty much sucks when it's up to more complex equations involving more views for a single constraint.
UIScrollViewcan be tricky when adding constraints. You should always add a subView that will behave as the content view for your UIScrollView and all your subsequent views will go inside this content view.
UIView1
|---UIScrollView
|---UIContentView
|---UIView2
|---UIImageView
Set your UIScrollViewconstraints as you would normally but set your content view to have leading, trailing, top and bottom to the UIScrollView but also add two more constraints which will be equal width and equal height to the viewController.view but will have a low priority (So that whichever direction your content will increase in, that constraint will break and automatically increase the content size of the scroll view by taking in the inferred height of the content view). Now go on and add constraints on all your subview as you normally would. Which i'm assuming would be:
Your topmost view will have top and leading and trailing to its superView and also a fixed height.
Your bottom view will have leading, trailing and bottom to its superView and also a fixed height.
Your UIImageViewwill have a leading, trailing and top to top most view and bottom to the bottom view.
Edit:
Here is the screenshot just in case (To show the view hierarchy with the content view's constraints in the inspector)

Disable Horizontal Scrolling of UIScrollView AutoLayout Resizable ScrollView

I have a UIScrollView which is getting resized on runtime according to some conditions. Now i used auto layout properly without using a single constraint extra or less. The first subview of scroll view has leading, trailing, top, bottom and equal width to scroll view and the height of the content view is managed by its inner content which is also changing depending on the runtime condition. Now according to my constraints my content view should not scroll horizontally as i used equal width to scrollview. But its happening. Can anyone suggest what am doing wrong? Here is the images of constraints i have used.
NOTE:- I have seen the posts on stack where this kind of question answered but my case is different.
Content UIView width should be equal to the width of UIScrollView's superview for instance, not UIScrollView itself.
In my case, I used to 'constraint to margin' option while I am adding constraint from storyboard. When I only add trailing and leading without relative to margin problem solved. I did not give any superview to my UIScrollView.

Resources