UIScrollView from IB does not scroll - ios

I am trying to implement a UIScrollView into my application.
Note:
ScreenSize: Freeform ( 345 ; 1000 )
Everything made with IB rather than programatically.
Auto Layout is activated in the application
view hierarchy:
I was doing the following steps:
Setting the ViewController to free form and 345/1000 px
Implementing a UIScrollView by dragging on screen
UIScrollView Size made 345/1000px
Dragging in anotherUIView named containerView.
All UIElements are put in the containerView.
Setting Constraints.
From here on I was trying several things. e.g. setting User Defined Runtime Attributes.
But it is still not scrollable.
Is there a way to fix this?

set bottom constraint of the last view in container view to the container view.
lastView.bottom = x + containerView.bottom

Related

UIScrollView Getting stuck

I am working on application in which I have UIScrollView which contains 3 subViews(UIView) and each subView has different controls & has different height. This all works fine but when I added constraint to UIScrollView and subView then UIScrollView isn't working.
I also added constraint to all the controls in subviews.
So please suggest me how to solve this problem?
It happened because UIScrollView content height and width dynamic at run time.
So whenever you apply constraint on UIScrollView then add
1.X position
2.y Position
3.width
4.height
Take a View as SubView on UIScrollView now apply Constraint
1.Leading on UIScrollView
2.Trailing on ScrollView
3.Top
4.Bottom
5.Height
6.Width
Then it work fine
For constraints to work properly,
You need to add a child view to UIScrollView and add your 3 views to that child view.
The main UIView and child view should have equal width constraint set.
For reference see this

UIScrollView Paging Autolayout & Storyboard

There are plenty of answers regarding scroll views with autolayout and plenty about scrollview paging, but I can't find a single thing that addresses both.
I'm not trying to do anything fancy...just 7 full-screen image views that I would like to scroll horizontally with paging, but for the sake of simplicity (ha!), I decided to attempt it all right in the storyboard.
The controller is set to freeform size with a width of 2240 (320*7). I then set it up the way Apple suggests for autolayout...
UIScrollview
/-----UIView
/----------Content (7 image views)
The scrollview has 0/0/0/0 constraints to all edges, as does the UIView inside.
When Paging Enabled is off, it behaves beautifully - exactly as expected. But once I turn Paging on, a swipe makes the view go crazy, scrolling the entire 2240 width, and then bouncing back and eventually landing on the proper page.
I know I have the tried-and-true option of just scrapping it all and doing it programmatically, but my stubbornness wants to figure this out. It must be possible!
I have a UIScrollView with paging and AutoLayout working perfectly fine. Here is my set up:
UIView // Main view
|---> Dummy UIView // See below
|---> UIScrollView
|---> Content UIView
|---> Page 1 Container
|---> Page 2 Container
The constraints I used are
Dummy UIView -> Parent UIView is whatever I want the size of the paging scrollview to be, and UIScrollView -> Dummy UIView is (0,0,0,0) on all sides. This is just regular auto layout stuff which creates a dummy UIView where I want to put the scrollview and a UIScrollView which completely fills the dummy UIView.
Refer to the Technote from Apple for AutoLayout and UIScrollViews: https://developer.apple.com/library/content/technotes/tn2154/_index.html
The content inside the scrollview has to have an intrinsic size. It cannot rely on the scrollview to get its size.
As indicated in the TechNote, set the constraints from all four sides of the Content View to the UIScrollView to (0,0,0,0). The exact values don't really matter since all you are telling the UIScrollView is that this is the view to get the contentSize from.
At this point Xcode will complain that Content View has no intrinsic size. And here is the trick: This is where we use the Dummy UIView that we created above. The size of the Dummy UIView is precisely the size of each page in the UIScrollView.
So we set the height of Content UIView equal to height of Dummy UIView and the width of the Content UIView equal to the number of pages times the width of the Dummy UIView using AutoLayout. (For the later change the multiplier in the constraint to be the number of pages).
Now create pages inside the Content UIView as you normally would and set Paging Enabled to yes on your UIScrollView and voila you have paging in a UIScrollView using AutoLayout.
I've tested this in IOS 6, 7 & 8.
Update:
Here is a sample project with this setup as requested:
https://github.com/kostub/PagingScrollView
Follow Working with Scroll Views to build paging UIScrollView with content in Interface Builder.
I'd also recommend using Stack View as a content view for your UIScrollView since it allows to essentially reduce layout complexity.
When you use traditional approach each entry view inside content view has 5 constraints at least:
leading to previous entry
top to parent
trailing to next entry
bottom to parent
equal width to scroll view
Stack View arrange its content automatically thus the only constraint each entry should have is "equal width to scroll view"
Check this project https://github.com/eugenebrusov/ios-stack-paging-scroll to see Stack View in action.
It is possible to use the scrollView's size to set the size of the contentView, contrary to https://developer.apple.com/library/ios/technotes/tn2154/_index.html; this was tested in iOS 8.2 beta 3.
Note that I did this programmatically, but hopefully this is useful to someone. The hierarchy is:
root: UIView
scrollView: UIScrollView
contentView: UIView
page0
page1
...
Add constraints to position scrollView relative to root and any siblings of scrollView.
Attach contentView sides to its superview (scrollView):
"H:|[contentView]|"
"V:|[contentView]|"
Add size equality constraints to contentView and scrollView; this is the part that contradicts TN2154 (which says "do not rely on the scroll view to get their size"):
contentView.height == scrollView.height
contentView.width == scrollView.width
Note: the above is made-up notation for a programmatically instantiated height constraint.
Lay out the pages relative to their superview(contentView); I did this by tacking the first page left/top to contentView left/top, and subsequent pages left/top to previous page right/top.
Credit to Koustub for getting me on the right track - his solution works, but with some fiddling I was able to eliminate the dummy view.

How to make a ScrollView with AutoLayout in Xcode5

In xcode 5 using storyboards how would one make a fully operational vertical scrolling scrollview, with AutoLayout ON?
Considering the subviews have hierarchy:
1.UIView
2.UIScrollView
3.UIView (lets call this UIDetailView to make things easier)
Please be specific from code to constraints to wether any of the views HAS to be smaller etc.
UIScrollView with Autolayout within Storyboards Just Works
I've seen a number of people recommending the 'Container View' approach, AKA brute force, to solving the problem that they don't understand. It is non-optimal since you now have lost a big advantage of the scrollview by making it think the content is the entire scrollview rather than the subviews immediately attached to the scrollview.
Here is how I did it in the example that follows
--UIScrollView
|-> UITextView
|-> UILabel
|-> UIOtherStuff
When placing a UIScrollView into a UIView in a Storyboard just pin the edges to the 4 sides of the UIScrollView to the UIView. Now add your content to the UIScrollView making sure that you provide a minimum of two constraints for each dimension. The great thing about Autolayout is that it figures out how big the contentSize of the scrollview, or UILabels for that matter, needs to be based upon the size of the content inside it. AKA intrinsicContentSize. So if you are given a warning 'Ambiguous content size for scrollView' you know that you have not given the content enough constraints. For example, you might have given Top, Bottom, Left, Right spacing distance between views but the subview you're constraining needs a height too since an infinite vertical plane like this UIScrollView could assume your view was from zero to infinitely high.
To put it another way the Apple guide on Autolayout by Example makes a simple 3 point plan for success:
Create the scroll view.
Place the UI element inside it.
Create constraints that fully define the width and height of the scroll view content.
That top TextView with 'Min melding til' is also growing as you type more lines into it and the whole ScrollView grows to contain it. While I override the UITextView class to return a modified height constraint, the ScrollView itself works correctly without coding.
One last thing, lots of posts related to Autolayout try the magical fix-all incantation translatesAutoresizingMaskIntoConstraints = NO. This is only necessary if the view is created programmatically.
This blog post details how to use a UIScrollView with Autolayout ON, using a pure autolayout approach. Note though that all constraints in the blog post are defined through the Storyboard.
The approach in the post assumes the following hierarchy:
1. View (main view of my UIViewController)
2. Scroll View (UIScrollView)
3. Container View (UIView)
4. Content View (e.g. UIImageView)
I guess the Container View will be your UIDetailView, and the Content View will be any UIView inside your UIDetailView.
https://happyteamlabs.com/blog/ios-how-to-use-uiscrollview-with-auto-layout-pure-auto-layout/
The documentation clearly states how to do this:
A UIScrollView in auto-layout will always resize itself to fit the content (UIDetailView).
So you have to set up your views like this:
UIView: Position with constraints.
UIScrollView: Bind to UIView with constraints.
UIDetailView: Set size (intrinsic content size), max out compression-resistance, set top-, bottom-, leading- and trailing constraints to UIScrollView to 0 manually.
I had a similar problem and i found relative simple solution similar to DJ S's from within Interface Builder using pure Autolayout without any code.
For proof-of-concept at first remove any constraint in View Controller to if see this works.
This is sample layout:
View (main view of my UIViewController)
Scroll View (UIScrollView)
Container View (UIView)
Content View (e.g. UIImageView)
A. Scroll View width/height should be smaller that Container View width/height
B. Container View should have some determinated width/height (may be explicit width/height )
C. Do Control-drag Container View to Scroll View and add only:
Leading Space to Container
Trailing Space to Container
D. Check out those two constraints and set "constant" value for both to 0
E. Run app and
Because of the new iPhone 6 and 6+ screen sizes, I had to make a few tweaks to DJ S's solution.
The goal
Position a UITextView inside a UIScrollView, and also have 15 pt spaces from the left/right screen edges.
Views
1. Main View (main view of my UIViewController)
2. Scroll View (UIScrollView)
3. Container View (UIView)
4. Text View (UITextView)
Solution
For the spaces, I added 15 pt horizontal trailing/leading spaces from UIScrollView->Main View. To make the UITextView's width relative to the screen width, I added an Equal Widths constraint from UITextView -> Main View and set the value to -30 (2 * the 15 pt horizontal space). Now, the UITextView's width will dynamically adjust for any screen size.
The UIScrollView should have Scrolling Enabled. The UITextView should not.

Content of scrollview changes size when scrolling

I'm using iOS 6 and Xcode 4.6 and with the Interface Builder I added to my controller a UIScrollView that uses all the available space. In this UIScrollView I added some views (a UIImageView, a UITextView and a UITableView (I disabled the scrolling for the UITextView and the UITableView)).
In the :
- (void) viewDidLayoutSubviews;
method I resized all my views by increasing their height (to fit with their respective content).
Then, I set the contentSize of my UIScrollView so that it fits with its content (my 3 views).
The resizing works and I can see them in my application when I run it.
Also, the scrolling is good (the contentSize is correct as I can scroll).
However, I have one big issue : as soon as I scroll, my 3 views are resized to their initial size (instead of keeping the size I assigned them via the frame property).
All my views are added with Interface Builder to my storyboard.
Do you know what I did wrong? Why my UIScrollView's content is reseting its size when I scroll?
Thank you for your help
You have auto layout enabled in your storyboard. When you scroll the scroll view, auto layout runs and resets your subview frames based on the constraints in the storyboard.
There are a few ways to fix this. One way is to turn off auto layout in your storyboard. Another way is to connect outlets to the constraints in your storyboard, and update the constraints (instead of setting the frames) to make auto layout put the views where you want them.

How to use UIScrollView in Storyboard

I have a scroll view with content that is 1000px tall and would like to be able to lay it out for easy design on the storyboard.
I know it can be done programmatically but I really want to be able to see it visually. Every time I put a scroll view on a view controller it won't scroll. Is it possible to get it to work like I want or do I have to do it in the code?
I'm answering my own question because I just spent 2 hours to find the solution and StackOverflow allows this QA style.
Start to finish here is how to make it work in storyboard.
1: go to you view controller and click on Attribute Inspector.
2: change Size to Freeform instead of Inferred.
3: Go to the main view on that storyboard, not your scrollview but rather the top level view.
4: Click Size Inspector and set this view to your desired size. I changed my height to 1000.
Now you will see that you storyboard has your view setup so you can see the entire height of your scroll for easy design.
5: Drop on a scrollview and stretch it so it takes up the whole view. You should now have a scrollview with size of 320,1000 sitting on a view in your view controller.
Now we need to make it scroll and need to make it show content correctly.
6: Click on your scrollview and click on Identity Inspector.
7: Add a User Defined runtime attribute with KeyPath of contentSize then type of SIZE and put in your content size. For me it is (320, 1000).
Since we want to see our whole scroll view on the storyboard we stretched it and it has a frame of 320,1000 but in order for this to work in our app we need to change the frame down to what the visible scrollview will be.
8: Add a runtime attribute with KeyPath frame with Type RECT and 0,0,320,416.
Now when we run our app we will have a visible scrollview has a frame of 0,0,320, 416 and can scroll down to 1000. We are able to layout our subviews and images and whatnot in Storyboard just the way we want them to appear. Then our runtime attributes make sure to display it properly. All of this without 1 line of code.
Here are the steps with Auto Layout that worked for me on XCode 8.2.1.
Select Size Inspector of View Controller, and change Simulated Size to Freeform with height 1000 instead of Fixed.
Rename the view of View Controller as RootView.
Drag a Scroll View as subview of RootView and rename it as ScrollView.
Add constraints for ScrollView:
ScrollView[Top, Bottom, Leading, Trailing] = RootView[Top, Bottom, Leading, Trailing]
Drag a Vertical Stack View as subview of ScrollView and rename it as ContentView.
Add constraints for ContentView:
ContentView.height = 1000
ContentView[Top, Bottom, Leading, Trailing, Width] = ScrollView[Top, Bottom, Leading, Trailing, Width]
Select Attributes Inspector of ContentView, and change Distribution to Fill Equally instead of Fill.
Drag a View as subview of ContentView and rename it as RedView.
Set Red as the background of RedView.
Drag a View as subview of ContentView and rename it as BlueView.
Set Blue as the background of BlueView.
Select RootView, and click Update Frames button.
Update Frames is a new button in Xcode8, instead of Resolve Auto Layout Issues button. It looks like a refresh button, located in the control bar below the Storyboard:
View hierarchy:
RootView
ScrollView
ContentView
RedView
BlueView
View Controller Scene (Height: 1000):
Run on iPhone7 (Height: 1334 / 2):
Here are the steps that worked for me on iOS 7 and XCode 5.
Drag a ViewController (it comes with UIView "View").
1.1 Select "View Controller" and select "File Inspector" and uncheck "Auto layout".
Drag a ScrollView (as child of ViewController's UIView "View")
Select ScrollView and open "Identity Inspector".
Enter "contentSize" for keyPath. Select "Size" for Type. And Enter {320, 1000} for value.
Note: Step 4 is simply saying that the scroller contains some content whose size is 320x1000 units. So setting contentSize will make scroller work.
Select View Controller, Select "Attributes Inspector" then select Freeform from Size.
Note: step 5 will allow us to change the size of "View" that the view controller comes with.
Select "View" and then select "Size Inspector".
Set Width to 320 and height to 1000.
Note: 5, 6 & 7 is purely for us to see stretched or entire expanded view inside StoryBoard.
Note: Make sure to unselect "Auto Layout" on View Controller.
Your View hierarchy should look like:
After hours of trial and error, I've found a very easy way to put contents into scrollviews that are 'offscreen'. Tested with XCode 5 & iOS 7. You can do this almost entirely in Storyboard, using 2 small tricks/workarounds :
Drag a viewcontroller onto your storyboard.
Drag a scrollView on this viewController, for the demo you can leave its size default,
covering the entire screen.
Now comes trick 1 : before adding any element to the scrollView, drag in a regular 'view' (This view will be made larger than the screen, and will contain all the sub elements like buttons, labels, ...let's call it the 'enclosing view').
Let this enclosing view's Y size in the size inspector to for example 800.
Drop in a label onto the enclosing view, somewhere at Y position 200, name it 'label 1'.
Trick 2 : make sure the enclosing view is selected (not the scrollView !), and set its Y position to for example -250, so you can add an item that is 'outside' the screen
Drop in a label, somewhere at the bottom of the screen, name it 'label 2'. This label is actually 'off screen'.
Reset the Y position of the enclosing view to 0, you'll no longer see label 2, as it was positioned off screen.
So far for the storyboard work, now you need to add a single line of code to the viewController's 'viewDidLoad' method to set the scrollViews contents so it contains the entire 'enclosing view'. I didn't find a way to do this in Storyboard:
- (void)viewDidLoad
{
[super viewDidLoad];
self.scrollView.contentSize = CGSizeMake(320, 800);
}
You can try doing this by adding a contentSize keyPath as a size to the scrollView in the Identity Inspector and setting it to (320, 1000).
I think Apple should make this easier in storyboard, in a TableViewController you can just scroll offscreen in Storyboard (just add 20 cells, and you'll see you can simply scroll), this should be possible with a ScrollViewController too.
Getting Scrolling to work in iOS7 and Auto-layout in iOS 7 and XCode 5.
In addition to this: https://stackoverflow.com/a/22489795/1553014
Apparently, all we need to do is:
Set all constraints to Scroll View (i.e. fix scroll view first)
Then set distance-from-scrollView constraint to the bottom most item to scroll view (which is the super view).
Note: Step 2 will tell storyboard where the last piece of content lies within Scroll view.
For this example, I have unchecked the Autolayout feature of the Interface builder. And, I'm still using (for no reason at all) the relatively old 4.6.1 version of Xcode.
Start with a view controller that has a scroll view over it (the main view).
1: Add a Container View, from the Object Library, to the scroll view. Notice that a new view controller is added to the storyboard and it is linked to the view controller with the scroll view.
2: Select the container view and, on the Size Inspector, make it anchor to top and left without auto resizing.
3: Change its height to 1000. (1000 is used for this example. You should apply the value that you require.)
4: Select the new view controller and, from the Attributes Inspector, change Size to Freeform.
5: Select the view of the new view controller and, on the size Inspector, change the height to 1000 (which is equal to the container view's height).
6: For your test later, while still on the view of the new view controller, add a label at the top and at the bottom of the view.
7: Select the scroll view from the original view controller. On the Identity inspector, add an attribute with the keyPath set to contentSize, type set to Size, and value set to {320, 1000} (or your container view's size).
8: Run on the 4-inch iPhone Simulator. You should be able to scroll from the top label up to the bottom label.
9: Run on the 3.5-inch iPhone Simulator. You should be able to scroll from the top label up to the bottom label.
Remember that Xcode 4.6.1 can only build for iOS6 and below. Using this approach and building for iOS6, I am still able to achieve the same results when the app is run on iOS7.
Note that within a UITableView, you can actually scroll the tableview by selecting a cell or an element in it and scrolling up or down with your trackpad.
For a UIScrollView, I like Alex's suggestion, but I would recommend temporarily changing the view controller to freeform, increasing the root view's height, building your UI (steps 1-5), and then changing it back to the standard inferred size when you are done so that you don't have to hard code content sizes in as runtime attributes. If you do that you are opening yourself up to a lot of maintenance issues trying to support both 3.5" and 4" devices, as well as the possibility of increased screen resolutions in the future.
Disclaimer :- Only for ios 9 and above (Stack View).
If you are deploying your app on ios 9 devices use a stack view.
Here are the steps :-
Add a scroll view with constraints - pin to left, right, bottom, top (without margins) to superview (view)
Add a stack view with same constraints to scroll view.
Stack View Other Constraints :- stackView.bottom = view.bottom and stackView.width = scrollView.width
Start adding your views. The scroll view will decide to scroll based on the size of the stack view (which is essentially your content view)
Here's how to setup a scrollview using Xcode 11
1 - Add scrollview and set top,bottom,leading and trailing constraints
2 - Add a Content View to the scrollview, drag a connection to the Content Layout Guide and select Leading, Top, Bottom and Trailing. Make sure to set its' values to 0 or the constants you want.
3 - Drag from the Content View to the Frame Layout Guide and select Equal Widths
4 - Set a height constraint constant to the Content View
i wanna put my 5 cents to accepted answer:
i've been researching topic for 2 days and finally found a solution that i will be using always from now on
go up to item 4 in accepted answer and forget about adding attributes of frames and contentsizes and so on
to make everything automatic just use solution from this link
everything is clear, easy, elegant and works like a charm on ios 7. i'm pretty glad with all that lol
You should only set the contentSize property on the viewDidAppear, like this sample:
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
self.scrollView.contentSize=CGSizeMake(306,400.0);
}
It solve the autolayout problems, and works fine on iOS7.
Here is a simple solution.
Set the size attribute of your view controller in the storyboard to "Freeform" and set the size you want. Make sure it's big enough to fit the full content of your scroll view.
Add your scroll view and set the constraints as you normally would. i.e. if you wants the scroll view to be the size of your view, then attach your top, bottom, leading, trailing margins to the superview as you normally would.
Now just make sure there are constraints in the subviews of the scrollview that connect the top and bottom of the scroll view. Same for left and right if you have horizontal scrolling.
In iOS7 I found that if I had a View inside a UIScrollView on a FreeForm-sized ViewController it would not scroll in the app, no matter what I did. I played around and found the following seemed to work, which uses no FreeForms:
Insert a UIScrollView inside the main View of a ViewController
Set the Autolayout constraints on the ScrollView as appropriate. For me I used 0 to Top
Layout guide and 0 to Bottom layout Guide
Inside the ScrollView, place a Container View. Set its height to whatever you want (e.g. 1000)
Add a Height constraint (1000) to the Container so it doesn't resize. The bottom will be past the end of the form.
Add the line [self.scrollView setContentSize:CGSizeMake(320, 1000)]; to the ViewController that contains the scrollView (which you've hooked up as a IBOutlet)
The ViewController (automatically added) that is associated with the Container will have the desired height (1000) in Interface Builder and will also scroll properly in the original view controller. You can now use the container's ViewController to layout your controls.
Here's a bit of a grubby answer that get's to the same solution for vertical scroll views, but (against the ethos of stackoverflow) doesn't answer the question. Instead of using a scrollView, just use a UITableView, drag a normal UIView into the header, and make it as big as you want, you can now scroll the content in storyboard.
Apparently you don't need to specify height at all! Which is great if it changes for some reason (you resize components or change font sizes).
I just followed this tutorial and everything worked: http://natashatherobot.com/ios-autolayout-scrollview/
(Side note: There is no need to implement viewDidLayoutSubviews unless you want to center the view, so the list of steps is even shorter).
Hope that helps!
The key is the contentSize.
This is often missing and not indicated when adding a UIScrollView.
Select the UIScrollView and select the Identity Inspector.
Add a contentSize keyPath as a size to the scrollView in the Identity Inspector and setting it to (320, 1000).
Scroll away.
If you are using auto-layout than best approach is to use UITableViewController with static cells in storyboard.
I have also once faced the problem with a view that require much more scrolling so change the UIScrollView with above mentioned technique.

Resources