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

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.

Related

Reverse scrollview height controlled by stack view in storyboard

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).

Scrollview in storyboard does not scroll

I created a scrollview in storyboard with multiple views but the scrollview does not scroll. See the screenshot. I have a scrollview with images and another view embedded that spans outside the view area. I would like the scroll view to scroll down but it does not when I see the code in the simulator.
You need to add a UIView with 1000(or whatever you want) height constant to scrollView and make the UIView equal width to view
ScrollView needs to know its scrollable area, so you need to provide information about width and height for ScrollView's content:
width - you can create empty view (with height constraint equal to 1), place it inside scrollView, set its leading and trailing constraints to scrollView and set width constraint equal to main view. Then, scrollView will know that its scrollable area has the same width as screen.
height - you need to provide top and bottom constraints for first and last components inside scrollView (and all components should have specified height). I guess you forgot about setting bottom constraint for the last item.

UIScrollView with Content View

I've been trying to create a UIScrollView for user registry but with no success. I'm using auto layout and all of the fields that go inside the scroll view are static. Because of the usual ambiguous height issue, I've added a UIView inside the scroll view, set the constraints to the margins of the scroll view and centered aligned it. After that I added all of the fields inside that Content View, in the storyboard.
The content fields have their constraints setup as you would expect, but when I get to the lowest field and set the bottom constraint to the bottom of the Content View then everything breaks.
I'm asked by Xcode to set the priority of some views, and when I do as is says, the Content View size stays the same and the views are shrunken.
I tried not to put the last bottom constraint and resize the Content View by code but the height is not resized as is should.
I'm looking for a good solution to do this in storyboards and auto layout.
Update: I added a bottom constraint with a low priority, but the content scroll view is not expanding to show all of the fields.
Add&Set ScrollView(UIScrollView)
Add&Set ContentView(UIView) with subviews
! Set ContentView Width equal to View Width
Set all subviews constraints
View1 should be tied to the top of the ContentView
View4 should be tied to the bottom of the ContentView
All SubView (View1, View2, View3, View4 ...) must have a height and distance between each other
P.s. In your case, if iOS > 9.0 you can replace ContentView with UIStackView
You are using auto layout so the size of the content view is determined by constraints. Follow the below steps to provide proper constraints:
Drag the Scroll View inside main view and provide constraints Top, Bottom, Leading and Trailing in align with Super View (Main View) as
per screenshot.
Take View which will contain your content and drag inside Scroll View. and provide the constraints Center X, Center Y, Top, Bottom,
Leading and Trailing in align with Scroll View as per screenshot
Put all the element inside content view which is a subview of scroll view and provide Top constraint relative to the element above
it, to make equal space between the elements (eg. label, button etc.)
(Make sure you provide required constraint for X-position)
Last element is "Register Account" button make sure you provide the Top Constraint relative to country and Bottom constraint relative to
superview (content view) and change the priority for Top or Bottom
constraint as per screenshot, otherwise it gives error.

Working with UIScrollViews

I've watched many Youtube videos on UIScrollView. Here, here and here. However nothing there is solving my issue.
Here I've a sample storyboard that I'm working with.
What I require:
The ViewController must be embedded in a Navigation Controller.
BlueView and CyanView will adjust its height accordingly to screen size based on aspect ratio.
YellowView will have a variable height as it contains a ContainerView with embedded UITableView or UICollectionView. Meaning my users can switch between views to look at similar data, with different format. Its information is grabbed from server side. This means that if there is no content, it doesn't require any scrolling. If there are many rows of data to fetch, scrolling should work to display all my information.
Problem faced
If I do not set specific heights to each of my views, IB will complain about the need for constraints on height or Y position.
When I try specifying the height in IB (so as to avoid the complain), during runtime, I attempt to change the height of my yellowView and myScrollView, the scrolling doesn't happen at all.
Inside the UIScrollView add a container View. That will contain rest of your views. So the heirarchy becomes like this:
|---UIScrollView
|----UIView
|---Blue View
|---Cyan View
|---Yellow View
This container view will have a leading, trailing and bottom and top to the UIScrollView. Also add a equal width and equal height constraint to your UIViewControllers main view. Give a priority of 250 to the equal height constraint. And then:
To the blue view, add a leading, trailing and top constraint to its superView and add the aspect ratio constraint. Tinker with the values till you see a UIView which looks nice to you.
To the cyan view, add a leading and trailing to its superView and add a top spacing to the blue view. Add the same aspect ratio as the blue view.
Now for your yellow view, add a top to the cyan view, and leading, trailing and bottom spacing to its superView.
Now your UITableView will have a leading, trailing, bottom and top to the container view or just directly use a UITableView.
If you wish to embed a UITableView inside the yellow view or just use a UITableView directly and expect the main UIScrollView to be scrollable, you will have to manually get a height constraint outlet for your UITableView and update it accordingly depending on the number of rows of the UITableView and height of each row so that the yellow view can increase its height based on the height of the embedded UITableView and hence update the content view accordingly which will in turn update the total content size of the UIScrollView.

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)

Resources