This post demonstrates how to use UIScrollView with Auto Layout. The Scroll View will contain one smaller view.
In my example, I will be using a UIImageView as the sole content of the scroll view.
If you need a multiple views inside the Scroll View, please refer to the following link instead:
iOS: How to use UIScrollView with Autolayout (Pure Autolayout Approach) – Multiple Content Views
I will be using the pure auto layout approach as stated in this note:
https://developer.apple.com/library/ios/technotes/tn2154/_index.html
First, I define the appearance of my screen in the storyboard. I have the following structure:
- View (main view of my UIViewController)
- Scroll View (UIScrollView)
- Container View (UIView)
- Content View (e.g. UIImageView)
- Container View (UIView)
- Scroll View (UIScrollView)
Next, define the constraints using the Storyboard.
- Scroll View (UIScrollView): 0 leading, trailing, top, and bottom spaces to superview
You can change this to what you want, e.g. 20 each for leading, trailing, top, and bottom spaces - Container View (UIView): 0 leading, trailing, top, and bottom spaces to the Scroll View
This is sort of fixed, unless you have a reason to do otherwise (e.g. to create a sort of a margin effect). - Content View (UIImageView): 0 leading, trailing, top, and bottom spaces to the Container View
This will make the container view expand when our UIImageView expands, which in turn automatically sets the contentSize of our Scroll View.
Our UIImageView size will depend on the image we put into it. Note that a UIImage must be set for the UIImageView so that the storyboard can compute the size. If you do not specify a UIImage, then storyboard will display “has ambiguous scrollable content” errors.
That’s it! Compile and run your app.
You can test the above by assigning a small-sized, medium-sized, and large-sized image to your UIImageView.
To add zooming, you need to set your UIViewController as the delegate of the UIScrollView, then return your Container View in the following delegate method:
1 |
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView |
References:
https://developer.apple.com/library/ios/technotes/tn2154/_index.html
http://stackoverflow.com/questions/13499467/uiscrollview-doesnt-use-autolayout-constraints
This worked well in Xcode5 with Auto Layout in a Storyboard if I had a single view at the deepest level, such as a UIImageView (as in the post) or a UITextView. I found this didn’t work with smaller views (manually setting larger intrinsicContentSize on them as well as IB based constraints to the ‘Container View’) to try to grow/scroll the Container View. I’m going to resort to loading the ‘Container View’ from a different nib. Good, clear instructions however, for the intended use case of a single piece of interior content that will driving the resizing based on its own intrinsic content size.
Clarification: I’m trying to use multiple smaller views in the container view that all sprawled out, would necessitate scrolling.
Thanks for the comment. I will try to look at how to include multiple smaller views inside the container view.
Hi,
did you in the meanwhile find out how this works if you have smaller views in the container view ?
Thanks in advance
Torsten
@Torsten, @Sohail
Please see the following post:
https://happyteamlabs.com/blog/ios-how-to-use-uiscrollview-with-autolayout-pure-autolayout-approach-multiple-smaller-views/
It demonstrates how to use UIScrollView with multiple content views, with Autolayout constraints.
This is fantastic! I simply made my UIView container view a lot taller than my screen (working on iPad so I made it 768×2048 to give me a double-height scrolled screen).
However, what do I need to change so that when I rotate the view the container view (UIView) stretches out width-wise?
Right now, it stays 768 wide and nothing I do with pinning it to the ScrollView makes it stretch out. The subviews within it seem to realign properly, however.
Hi ksignorini,
On change of orientation, you should update your container view’s height and width constraints.
You can swap the width and height constraints constant values if orientation changed from landscape to portrait and vice versa.
Good evening!
I am trying to do the same as well… I did:
– (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
_containerView.frame = CGRectMake(0, 0, 1024, 768);
_imageView.frame = CGRectMake(0, 0, 1024, 768);
[_scrollView setContentSize:CGSizeMake(1024, 768)];
}
else
{
_containerView.frame = CGRectMake(0, 0, 768, 1024);
_imageView.frame = CGRectMake(0, 0, 768, 1024);
[_scrollView setContentSize:CGSizeMake(768, 1024)];
}
}
But it doesn’t work! Any ideas?!
If you are using auto layout, you need to update the constants of your constraints, not the frame of your views.
First, create an IBOutlet NSAutoLayoutConstraint to your desired constraints (e.g. width and height).
Then, update that when device is rotated.
For example:
widthConstraint.constant = 768;
heightConstraint.constant = 1024;
Hi!
Its a great tutorial!
However I am getting some warning on reproducing the above steps. It says Ambiguous Layout, width is ambiguous and height is ambiguous. How do I resolve this?
Thanks.
It means you are either missing a constraint or there is an extra constraint that conflicts with the other ones.
Did you define the same (and exactly the same) constraints as posted in the article?
I am following as the article says, however I am still facing ambiguity issues. Here is a snap of my storyboard to better explain my problem.
https://docs.google.com/file/d/0B6WaP7Z_PtDWMzV4MXlmRlg1S00/edit
https://docs.google.com/file/d/0B6WaP7Z_PtDWRlhCLTVISlRNeGs/edit
Thanks
@Sara
It seems that you have another view (UIImageView) which is a sibling of the Scroll View.
Have you defined constraints for the UIImageView?
Hello Happy Team Labs,
Great tutorial! I followed all the steps and I can get everything working perfectly; however, when I tried the same process with a view that contained UIButtons, all of the UIButtons lost functionality. Any ideas why this happened and/or how to fix it?
Thank you for the feedback.
Regarding your question, what do you mean by “UIButtons lost functionality”?
Did the buttons stop calling their target methods?
That’s okay! 🙂
Yes, exactly.
Well this is embarrassing. Turns out I just somehow deleted the outlets for my buttons :S Sorry!
No I haven’t defined any constraints for the image. Do I need to? If so which constraints should I define? Thanks
What does the image view do?
For starters, you can try defining fixed height, fixed width, fixed X position, and fixed Y position.
If this still does not work, can you create a sample project somewhere (GitHub, etc.)?
Sorry but I just realised that I don’t need that image view. So I have removed that. however I am still facing the same issue. https://docs.google.com/file/d/0B6WaP7Z_PtDWd0ZQeHQwY3ZMcGc/edit
Thanks
Hi Sara,
There is an error because you do not have content inside the Container view, which means Storyboard cannot compute the size of the Container view too. You can try adding a UIImageView inside the Container view with constraints as specified in the tutorial. Also, don’t forget to set a UIImage for the UIImageView.
If you do not want to add anything inside the Container view, to remove the errors, you may try adding additional constraints to the Container view. Please try adding fixed width and fixed height constraints to the Container view, and see what happens.
Regards.
Hi
I tried both options, 1. I have content in my container view which I added into the view controller which came along with the container view. https://docs.google.com/file/d/0B6WaP7Z_PtDWcVJhQTgzcVE3NnM/edit
2. I tried adding height and width constraints, but that didn’t help as well. https://docs.google.com/file/d/0B6WaP7Z_PtDWd2hETXZPQjFvcXM/edit
3. Also when I am trying to add an image view to the container view, its either goes above or below, but not into it.
Nothing seems to help.
Thanks
Based on your screenshot, I think your 2 is okay. No errors, just a warning (yellow icon, not red).
Can you post a screenshot of the warning in 2?
I’m guessing that the warning is about something like “Misplaced Views -> expected is different from actual”.
You can remove the warning by:
1. Select Formulaire View Controller from the Storyboard layout hierarchy pane (left side).
2. Editor > Resolve Auto Layout Issues > Update All Frames in Formulaire View Controller
Yes. You are right, the warning when I add height and width constraint is regarding Misplaced Views. Here is the screenshot. https://drive.google.com/file/d/0B6WaP7Z_PtDWQm94cklvU2JuTFk/edit?usp=sharing
Thank you so much!! It worked! 🙂
No problem 🙂
Hi, thanks for your article. A question though, why do you need the container view around the image view ? Sticking the image view directly in the scroll view seems to work too…
Yes, sticking the image view directly in the scroll view will work too, and its the simplest way to do it.
But, if you need a sort of a margin effect, you will need a containing view for your image view (though in this post, the margin is 0, but the matter about the margin is added as a side comment).
Hey,
Can you help me out with making scrollview work similarly in 3.5 and 4inch phone?
StoryBoard with constraints: http://www.pacmac.co.in/img_show/1.png
Code:
[self.scroller setBackgroundColor:[UIColor blueColor]];
[self.container setBackgroundColor:[UIColor orangeColor]];
self.scroller.contentInset=UIEdgeInsetsMake(44.0,0.0,0.0,0.0);
CGPoint currentOff = self.scroller.contentOffset;
currentOff.y+=44;
[self.scroller setContentOffset:currentOff animated: NO];
Output:
In 3.5″ screen: http://www.pacmac.co.in/img_show/2.png
In 4″ screen: http://www.pacmac.co.in/img_show/3.png -> When drag down -> http://www.pacmac.co.in/img_show/4.png
The 4″ screen result is what I want, By default only container view should be seen, And when drag down scrollview(A search bar in that area) can be seen..
Thank you for this great tutorial!
Is self.scroller the UIScrollView?
And self.container the UIView inside the UIScrollView?
Yes, I can send you the project if you’d like to see?
Thanks for the quick reply.
Xcode Project of the same: http://www.pacmac.co.in/img_show/test.zip
Hi @Aakash
I’m very sorry for the late reply. I have been very busy this past month, and was only able to view comments today.
Have you managed to fix your problem?
I have tried to recreate this and the error that I am getting is –
Misplaced Views – UIView (container) and UIImageView (content).
My UIImageView is set to Aspect Fit.
Screenshot of constraints, same as yours as far as I can tell –
http://i58.tinypic.com/n5mnnn.png
Output running in Simulator 4Inch Retina –
http://i61.tinypic.com/kec2sw.png
Hi @Usman,
Sorry for the very late reply. I have been very busy this past month, and only had the time to look into comments now.
The Misplaced Views message is just a warning, and not an error.
Is the current output not okay?
To remove the warning, you can adjust the position of the views by:
1. Open storyboard
2. Select affected view controller (in your case, Photo View Controller View Controller)
3. Clicker Editor (in the menu)
4. Resolve Auto Layout Issues -> Update All Frames in Photo View Controller View Controller
+1 for this. One of the most succinctly perfect UIScrollView tutorials available.
Thank you 🙂
Hi,
Thanks for this article. But I am facing some problem while zooming the Scroll View. I have implement same article with added zooming feature on my image View but the problem is:
1) Portrait mode: Looks good
2) Portrait mode with ZOOM: Looks good
3) Turn to landscape with ZOOM enabled: Whole layout spoiled.
Can you anybody suggest anything?
Kindly update the code for this tutorial
Hi ,
Thank you for this great article.I m facing some issues with zooming out the image.The view(container) becomes small and its not centered.Could you please help me with this?