IOS scrollview ambiguous scrollable content height in case of autolayout - ios

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.

Related

"Scrollable content size is ambiguous to "ScrollView"

I am a little stuck with the ScrollView in Swift and Xcode 11.
My goal is a simple ScrollView with Labels and Textfields. Each label describes what the textfields are used for. For example there is a Label "Name", so you have to enter your name in the textfield under the label. For this I need a ScrollView because the App I am coding requires a few more information. When I am trying to put this in a ScrollView I am constantly getting the following error:
"Scrollable content size is ambiguous to ScrollView".
In order to find help I searched the internet and for example found this question: UIScrollView Scrollable Content Size Ambiguity.
Unfortunatly it didn't solve my problem. So I decided to create a small test project with the following:
- I created a project as a Single View Application
- I added a ScrollView to the ViewController
- I clicked on the constrains-Button at the canvas
- I selected 0,0,0,0 for leading/top/trailing/bottom.
- I clicked on "add 4 Constrains
- Now the warning appeared. Also the ScrollView was not resized to the ViewController... I don't know why.
- I added a UIView inside the ScrollView and set the same constrains, this time according to the ScrollView.
- The UIView (Content view) got an extra constrain: Equal width with the root view
- Now I added two Buttons, one with the text "Hello" and the other one with "world" on it.
- The "hello"-Button received the following constrains: 16 to leading, trailing and top, as well as a fixed height of 30.
- The "world"-Button got the following constrains: 16 to bottom, leading, trailing and over a 1000 so you can scroll through the ScrollView.
After all these steps the error is still there and if I run the app the "hello"-Button is at the top of the screen and the "world"-Button is at the bottom and I can't scroll.
Can maybe anyone help me fixing this issue. I am looking forward to every answer! Thank you for your help in advance!
Here is the trick that worked for me:
Add a ScrollView to your wished ViewController.
Select it in the Outline and open its size inspector.
Uncheck there the option "Content Layout Guides".
Now set leading/top/trailing and bottom constrains to 0 of the ScrollView.
Add in a UIView and constrain its leading/top/trailing and bottom also to 0.
Add an equal width constrain to the UIView. (The width needs to be equal the width of the view from the ViewController, with this way you are disabeling horizontal scrolling).
The warning will disappear if every element inside the UIView is chained vertically. This means, that the top element has a constrain to the top of the view and to the element under it and so on. The last element needs a constrain to the bottom of the view.
If you followed this steps you should be fine with ScrollViews. This way you also can add as many content as you want to the bottom and the ScrollView will extend dynamically.
I hope I explained it well enough.
It sounds like you're on the right track, and really close.
The first part is absolutely right - you add your ScrollView and pin it to zero for the top, trailing, bottom, and leading constraints. That makes it take up your whole screen.
Then you drop a plain old UIView into the ScrollView, and pin its top, trailing, bottom, and leading constraints to the ScrollView (all as zero again). Then you set the UIView to have an equal width to the ScrollView. The last thing is to set the UIView's height as equal to the ScrollView's height, but you change one thing: you set the priority of this constraint to be low (250). That's basically what allows the UIView to exceed the size of the ScrollView, so you can then scroll.
All you do then is add your buttons, etc inside the UIView, so you place them in relation to it rather than the ScrollView, and pin or align them as you wish.
Add a total of 9 constraints
1 - 4: ScrollView to Superview (leading, top, trailing & bottom)
5 - 8: Content view to Content Layout guide (leading, top, trailing & bottom)
9: Content view Width equals width to Frame Layout Guide.
But when you do this (right-click drag and drop) 7 & 8 constrains (trailing & bottom constrains to Content Layout guide) will have constant values. (check image below).
Just make them zero. Now it worked.

I need to scroll a floating(fixed) UIView in my storyboard after a specific point in UIScrollView

In my storyboard, I have a parent UIScrollView in which I have a UIView of height about 2000px.
I have designed the whole view & placed an another UIView at bottom of parent scroll view so that it will be fixed in the UI. But at the specific point, I need to place that UIView(i.e.fixed) to get scrolled. Like after I scroll a UILabel, I want to scroll that UIView below that & get disappeared from the bottom.
I know its hard to explain but I am stuck at it for so long.
P.S. I'm using AutoLayout.
In this case it is probably best to have the view outside the scroll view but connect constraints to the inner view as well. You use priorities to control those constraints.
In your case you would decrease your bottom constraint priority (to 500 for instance). And you would add a constraint like outsideView.top <= insideView.bottom. So connect the outside view to one of the views inside the scroll view and create the relation be smaller (or greater if the 2 items are reversed) or equal to that view point.
To create a demo of this start a new project and open Main.storyboard:
Add a scroll view with constraints to leading, trailing, top, bottom
Add a blank UIView (now called innerView) inside the scroll view and add leading, trailing, top, bottom constraints
Add a height constraint to innerView to 2000
Add an equal width constraint between innerView and your scroll view
Set bottom constraint between innerView and scroll view to 100
Set a distinct color to innerView to see the effect
All other constraints should be set to 0
Add another UIView on the top level (now called outerView)
Pin outer view to leading, trailing and bottom. Also add a height constraint to 50
Set a distinct color to outerView to see the effect.
By now you should have a scrollable scroll view and a fixed view at the bottom if you run the app.
Now connect outerView with innerView and select "vertical spacing"
Double click the newly created constraint and modify it:
(If needed) Reverse first and second item so that the outer view is first item
Change relation to "less then or equal"
(If needed) select outerView.top
(If needed) select innerView.bottom
Set constant to zero
Select outerView and find bottom constraint to safe area (or superview) and set its priority to 500.
Now run the app. If all is correct your fixed view will be fixed until you scroll down far enough. After 2000px is visible the fixed view will be scrolling with scroll view.
You can naturally pin it to any view in scroll view to get any possible effect you need.
I hope this is descriptive enough. Good luck.

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)

UIScrollView's Content View is ignoring equal width constraint to main view on Xcode 6

I've added a Scroll View that contains a content view. The scrollview's constraints keep it just below my progress bar and attached to the leading, trailing, and bottom of the superview. The content view's constraints hold it to the sides of the scroll view, with one additional constraint: equal the width of the superview.
Everything looks great on the storyboard preview, but at runtime the scrollview's calculated width increases.
Basically, it seems that AutoLayout is ignoring my constraint to constrain the width of the content view, and instead just allows the content view to get as large as it wants to fit the content in.
Here are my constraints:
Thank you so much for helping me get over this roadblock! I've been banging my head against the wall for days.
Here are some things I would try. I don't have comment privileges yet, otherwise I would ask for elaborations:
Are there any outputs in the console for Xcode? Generally when Autolayout is forced to break constraints, it tells you about it in the logs.
So to be clear, for the Content View, you have a constraint that sets the width equal to the ScrollView, as well as constraints to match the Leading and Trailing edges to the ScrollView?
If the constraint is not being followed then either the ScrollView is also expanding somehow, or the constraint conflicts with another constraint, and the width-matching constraint got broken somewhere along the way.

Resources