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

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!

Related

iOS - UIScrollView not scrolling, though scroll bar is shown

I have a Scroll View, and inside it a UIView called "Content View", that contains all of my elements.
The Content view is equal to the Scroll view's top, bottom, leading and trailing. Also equal its width & height.
I also added self.scrollView.contentSize = self.contentView.frame.size
in ViewDidLoad.
When I scroll I can see a scroll bar going up and down on the side, and it seems like the page length is correct according to the bar, but the content itself does not scroll as you can see here:
What am I doing wrong?
Thanks!
I ran into this issue (or something very similar) where the scrollbar would scroll, but the content did not. It drove me crazy for a while because it seemed like everything inside of the scrollview was constrained correctly in Interface Builder. Finally, I noticed that the top item within the scrollview container (container = the view inside of the UIScrollView that contained all of my views) was constrained to the top by aligning with a view outside of the scrollview.
Once I removed the constraint that was aligning the top with an external view from the ScrollView and instead aligned it with the main container within the UIScrollView, everything worked fine. Hopefully that helps in case someone runs into this issue and the other mentioned solutions don't fix it.
The Content view is equal to the Scroll view's top, bottom, leading
and trailing. Also equal its width & height.
You need to remove the width and height constraints. Top, bottom, leading and trailing should stay. Also, remove that contentSize setting from viewDidLoad.
I assume you want vertical scroll. In that case, you should set contentView's width constraint to be equal to View's width (not scrollView's but View's which is the root of the hierarchy).
That should do the trick, assuming that vertical constraints of contentView's children are properly set up.
By default Content Layout Guides is enabled for a Scroll View. So when we pin the content view (main view inside the scroll view) on all 4 sides and equal width and equal height (with lower priority), it takes Frame Layout Guide for top constraint, this is the root cause of the issue where only scroll indicator moves and not the entire content.
You can uncheck Content Layout Guides from Scroll View Size Inspector. Or if you want to use it change the top constraint to Content Layout Guide instead of Frame Guide Layout and it worked as charm. Please refer below screenshot.
The 1st thing I had to do is what user3199693 said: remove that line from viewDidLoad (that made the wrong scroll bar I saw to go away). Also I set contentView's width constraint to be equal to top View's width, as he said.
That was good, but still didn't solve the problem. What did help was equal the height of the content view with top view.
Got the idea from here.

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 Vertical Scroll + Autolayout

I want to do something simple, yet Apple loves to overcomplicate things for developers (quite ironic). I want to create a vertically scrollable screen. Basically a longer screen that I can scroll through. The problem is that it either doesn't scroll or the content (a label for demo purposes) is fixed on the screen (e.g. centered).
I looked at multiple tutorials but still didn't fully understand it because the inner workings aren't fully explained.
So from what I understand, it goes the following:
You place a UIScrollView on top of the main UIView
You set the UIScrollView's margins to 0-0-0-0
You place a content view UIView inside the UIScrollView
You set it's margins to 0-0-0-0 related to both the main UIView and the UIScrollView
You set the UIScrollView and content UIView's height & width (in my case I chose 1000 for height and screen width for width since I want only vertical scroll)
You set the UIScrollView.contentSize to something bigger than the screen
You add the content and align it to the content UIView
So what am I missing or adding when I shouldn't? If anyone can explain how this is done quickly, please do so.
Quite a lot of this is wrong:
So from what I understand, it goes the following:
You place a UIScrollView on top of the main UIView
You set the UIScrollView's margins to 0-0-0-0
You place a content view UIView inside the UIScrollView
You set it's margins to 0-0-0-0 related to both the main UIView and the UIScrollView
You set the UIScrollView and content UIView's height & width (in my case I chose 1000 for height and screen width for width since I want only vertical scroll)
You set the UIScrollView.contentSize to something bigger than the screen
You add the content and align it to the content UIView
There are various strategies for making a scroll view scrollable under auto layout. The "content view" strategy is perfectly valid, and very convenient, though it is not the only possible strategy. Since you seem to imply you want to use it, let's use it:
Pin the scroll view's top, bottom, left, and right with constraints to main view. Typically these constraints will have a zero constant, but no law requires this.
Give the scroll view exactly one immediate subview, a "content view". Pin the content view's top, bottom, left, and right with constraints to the scroll view. These constraints must have a zero constant.
Give the content view height and width constraints. Set their constant values absolutely. Experimentally, use large numbers. As you've said, width of zero and height of 1000 will give you vertical scrolling on a screen smaller than 1000 height.
Now stop. Don't add any more constraints, and don't set the scroll view's content size in any other way. You are finished. The scroll view is now scrollable, even though there is nothing visible inside it — provided the height or width constraints constant values are larger than the actual height or width of the scroll view at runtime. And you can run the project and see that this is true.
You are now free to populate the content view.
You don't have to put a UIView inside the scroll view. You can just add whatever objects you want and set objects frame within the scrollview. The scrollable area is set by the contentSize property of UIScrollView.
Some things you will want to make sure to do:
1) Add <UIScrollViewDelegate> to your .h file
2) set scrollview.delegate = self;
3) Set scrollview.contentsize = CGSizeMake(something bigger than the screen)
4) make sure the scrollview is scrollable with scrollview.scrollEnabled = YES;

Swift - UIScrollView Scrolls Partially

My problem is slightly different from other's 'Swift UIScrollView' problems when using auto layout:
Problem:
Unlike others, when I run my app, it scrolls. My problem is that the scroll cuts off the bottom 20-30% of the content. I can pull to see the buttons did build and are down there, but when I let it go the scroll snaps back to a false bottom which cuts off my content!!! I've been trying, for days, to fix it to scroll the entire height but it continues to cut off!!
Description of app:
I used auto layout to layout 6 buttons and labels. Each button a rectangular image, with a label directly beneath it. (sorry, the site won't let me post pictures!)
I have my views arranged like this:
MainView > ScrollView > ContentView > Buttons & Labels
I have my contentView pinned to my ScrollView and my ScrollView pinned to my MainView. My buttons and labels all have constraints that are building correctly, to create a list that looks like:
Rectangular button
Label beneath it
Spacing
Rectangular button
Label beneath it
Spacing
Etc.
Can anyone tell me why I can't scroll the full length of the view?
Your description of how your items are constrained is vague, so I'm going to list all of the constraints you need to make this work. Then you can compare what you have to what you need and adjust accordingly.
Your ScrollView should be pinned on all 4 sides to the MainView. (This isn't absolutely necessary. You can constrain your ScrollView however you want, but make sure it can grow as the device and/or orientation changes).
Your ContentView should be pinned on all 4 sides to the ScrollView with offsets of 0.
Since you want your ScrollView to scroll vertically only, constrain the width of the ContentView to the width of the ScrollView using an Equal Widths constraint. To do this, in the Document Outline view, Control-drag from your ContentView to your ScrollView and select Equal Widths from the pop up.
The height of ContentView will be set by the sum total height of everything in it. In order for this to work, your topmost button needs to be pinned to the top of the ContentView, all of your buttons and labels should be pinned to their nearest neighbors, and the bottommost label should be pinned to the bottom of the ContentView. In addition, all of your buttons and labels should have constraints for their widths and heights. I would suggest setting an explicit width constraint and explicit height constraint for your buttons and centering them horizontally in the ContentView. For your labels, set an explicit height constraint and pin the left and right edges to the ContentView.
If you have these constraints and no other ones, your ContentView will be properly sized.
Using contentView, like you said, usually fixes the issue. So chances are you need to take a second look at your contraints. Maybe try this solution in a clean/new project to see that it works. (it does work). My guess would be that some of your constraints conflict each other.
Otherwise I think it would be a good idea to setContentSize of your scrollView in your viewDidLoad.
Another hack would be to place 2 UI objects with their alphas set to zero on the right top corner and left bottom corner. This would hint scrollView to set its contentSize.

UIScrollView content size fixed to 600x600(Main.storyboard size)

I've been facing this issue from past 2 weeks and not yet got a solution.
I'm using UIScrollview in my application where the problem exists.
Generally in my app, there is dynamic text and images with different sizes will come from webservices. For example, imagine the Facebook Newsfeed. My application is similar to the Facebook newsfeed. Sometimes, there will be only text, sometimes there will be text and images. And comments for that post.
As i've seen in many links, the heirrarchy i'm following is SuperView-->UIScrollView-->Content View and the elements are placed in that content view. I'm assigning the constraints from the elements in the contentview to the Superview (ContentView --- constraints -- SuperView). When the content in the view exceeds the size of the superview, it has to scroll. But the scrollview content size is limited to the size of 600x600 i.e., in main.storyboard, when we design for W any x H any size. I've seen many tutorials and searched many sites. But following them gives me no luck.
Any help is appreciable.
Here is how to set up a scrollView in Interface Builder from scratch that works with Auto Layout.
Start with a new ViewController. Drag out a scrollView such that it fills the view. Untick Constrain to margins and constrain the left, top, right, and bottom edges of this scrollView to the left, top, right, and bottom of its superview with offsets of 0. This allows the scollView to fill the screen on any device in any orientation. You can make your scrollView take up less of the screen if you like, just make sure it is fully contrained.
Add a view to your scrollView. This should be the only top level view on your scrollView and it will serve as your contentView.
Constrain the left, top, right, and bottom edges of this contentView to the left, top, right, and bottom of the scrollView with offsets of 0. At this point, you will see warnings about ambiguous content size. That is because you haven't told it yet how big your content view will be.
To size the contentView, add width and height constraints to the contentView. If you want it to scroll, the width and height must be larger than the width and height of the scrollView itself. If you only want to scroll vertically, set the width of the contentView to be equal to the width of the scrollView. To do this, in the Document Outline view, control-drag from the contentView to the scrollView and select Equal Widths from the pop up.
If you want to be able to change the height of your contentView from code (to account for dynamic content), first create a height constraint for your contentView by control-dragging within the contentView and selecting Height from the pop up. Create an IBOutlet to the height constraint by control-dragging from the height constraint (found in the Document Outline view) to your ViewController's code. Give the outlet a name like scrollViewHeight then set the height with a value like scrollViewHeight.constant = 2000 when you need to change the scrollView's height.
Simply add your UIScrollView to your UIViewController's view in the storyboard and add the appropriate constraints in the interface builder.
Then, build your content view in the code and give it any frame you want, now start adding your controls to this content view and calculate the size of each one (especially the height), and at the end you have the total height of your controls.
Now set the frame of the content view to match that height and add it as a sub view to your scroll view, then set the content size in the code like this:
_scrollView.contentSize = contentView.frame.size;
Another note, do this changes to the sizes in the viewDidLayoutSubviews to avoid any problems with different screen sizes but be careful, this event is called many times so have a BOOL or something to ensure that the code that creates the view and add it to the scroll view is executed once, e.g. like this
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (! built) {
// Do everything I explained above here
built = YES;
[self.view layoutSubviews];
}
}

Resources