I have a screen where the main view has a UIScrollView which contains a UIView which in turn contains 3 UIViews placed vertically, I have set the constraints accordingly, trying setting contentSize in both viewDidLoad and viewDidLayoutSubviews, all to no avail. I have created a sample project with the issue I'm facing at https://github.com/modsoussi/ScrollViewTest.
I'm surprised Interface Builder isn't showing a Constraints error or warning...
When using auto-layout, the contents of the scroll view define the contentSize. That means the contents (in your case, a single UIView holding 3 smaller UIViews) must have a constraint to the Top, Leading, Trailing and Bottom of its superview (the scroll view)... and it must have a Height and Width.
In your storyboard, delete the "Center Vertically" constraint, and add a Height constraint (of 1000) to the "content" view. Then delete your scrollView.contentSize = ... line from code. Run the app, and you should have no problem scrolling.
Related
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.
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.
I am adding more than 8-9 controls in my ScrollView but I am not able to set ContaintSize of that ScrollView so that I can able to scroll and view all controlls.
I HAVE SET below constrains to my scrollview and add some controls into my scroll view with the help of contain view.
Scrollview.top respect to his superview
Scrollview.bottom respect to his superview
Scrollview.leading respect to his superview
Scrollview.trailling reapect to his superview
Than I have added UIView as contain view and set all constrain respect to scrollview.
Than added all controls into view but still its not scrolling as expected.
By below code I am able to set containview but its ststic one and cant assume that 1000 is my contanent height.
Scrollview.contentsize = CGSizeMake (Scrollview.frame.size.width,1000);
Above part is static as I have many lable with multiple line in it.
All data is dynamic comes from server si cant set it static.
Can any one help me out how to set autolayout of scrollview so I can get dynamic content size?
Edit: some time I am getting autolayout error into storyboard like below.
Scrollview has ambiguous scrollable content height
An while i reslove conflicts its not showing proper scrollview in my screen.
Faced the same issue recently. I'm sure that you did your research but here is the guide I used, nonetheless.
https://www.natashatherobot.com/ios-autolayout-scrollview/
Also if you have many labels it would be good consider using a 'UITableView' or a 'UIStackView'.
Edit
Make sure you center the scroll view vertically and horizontally in respect to its container.
You have to define constraints for the scroll view like this..
ScrollView :
top ,left , bottom, right pinned to superview.
ContainerView:
top, left , bottom , right pinned to scroll view
width pinned to main view
And make sure that every subview inside the container view should have constraints in such a way that it should define the height of container view.
As i understand your issue you forgot to set the height constraint of your contentView, just try by setting it.
No need to set the fix height of scrollView's contentSize, please see the below code.
self.scrollview.contentSize = CGSizeMake(self.contentView.frame.size.width, contentView.frame.origin.y + contentView.frame.size.height + 10);
Note: you need to add height and width constraint of contentView if you need scroll according to it.
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)
Hi I am developing small IOS application in which I am using scrollview with auto-layout.Inside scroll I am adding two more views. I am using IB and auto-layout constraints. I am adding two views in side one after another in vertical manner. I have added outer constraints like trailing, leading, top, bottom space. I also added height constraints for both views. Till this everything is working fine.
But my view1 has some dynamic content. For that reason I want to make height constraint greater than equal to instead of equal to.
So how to resolve this problem. Need some help. Thank you.
You should follow the approach below.
First of all, here are some important things about scroll Views which are important for auto layout:
UIScrollView changes its bounds automatically.
UIScrollView needs a content View(in UI) for getting content size for scrolling which works smoothly for auto layout.
UIScrollView's top and bottom constraint should connected to top and bottom layout guide (For most of the cases, not all).
As per your problem:
First Approach: You have UIScrollView, so just insert one UIView inside it and consider it as Content View. After that put your two UIViews inside the UIView (Content View).
So the Hierarchy is: MainView --> UIScollView --> UIView (ContentView) --> firstView & Second View. Now we are going to give constraints to all of them.
For UIScrollView, connect TOP and BOTTOM constraints to TOP & Bottom Layout Guide and LEADING and TRAILING to the Main View.
For UIView (Content View) it is very important to give constraints LEADING, TRAILING, TOP, BOTTOM to the UIScrollView and to give the explicit height (normal height constraint) to your contentView which is appropriate for scrolling (e.g 1200). Also make it horizontally center in container.
Now give constraints to your first view: LEADING, TRAILING, TOP to ContentView and give explicit height (normal height constraint). Don't try to modify it in greater than equal right now - we will do this later. Then, give constraint to second view Leading, Trailing to ContentView, Top to FirstView, Bottom to Content View and Explicit Height (what ever you want). Now, try to modify the Height constraint of first view from equal -> greater than equal - it will definitely work.
Second Approach (Easy and Simple): After giving constraint as per first point, for changing height of first View dynamically you can create an IBOutlet of height constraint of first view to your class and as per your requirement you can change the constraint's constant value (as per you want the height of first view) in any method or button action so it will change in run time. You can also consider it is a fine trick when you want to hide your views so just change their Height constraint's constant to 0 so it will hide and at the time of unhide, again set the constant value of same to desired value so you can also easily play with hide and unhide functionality of view which is little bit difficult in auto layout from other ways.
I would make this constraint as type equals and give it low priority. Then, during adding dynamic content, you may just add another constraint with higher priority.
If you load this UIView from xib just make sure you provide constraint with higher priority.