Content of scrollview changes size when scrolling - ios

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.

Related

UIScrollView in Xcode using Springs and Struts

I am managing an application in iOS using swift language and Spring and Struts for positioning. For some reasons I have to use UIScrollView in it. But I couldn't found it's correct way of implementing using "Springs and Struts" layout positioning technique.
I am setting the view height to "FreeForm" and then Content View height to 1000 px but all things are showing in the same screen size.
Using Struts and Springs is no longer recommend, you should be using AutoLayout.
However, if you must:
1) Disable / Uncheck "Use Auto Layout" in Files Inspector for the View Controller, this will also disable trait variations.
2) Change your Simulated Size to "Fixed" in the Size Inspector for the view controller. Ensure the Simulated Metrics for Size is set to "Inferred" in the Attributes inspector for the view controller.
3) Add views and set the autoresizing mask's "struts and springs" to tell the view how to grow and shrink within its superview.
4) set the view's desired frame rectangle to the position relative to it's super view.
You will have to set the scroll view's height manually, since there are no other views to constrain the frame and allow the autoresizing to kick in. To do this, set scrollView's content size after the view controller loads. see viewDidAppear(_:) Otherwise the layout engine cannot determine the vertical spacing between the top of the button to the top of its superview (the scrollView).
Again, this isn't advisable and you should consider migrating to AutoLayout.
The setting for "FreeForm" is only for interface builder, so you can have a complete view of all the content in your scroll view, but it won't reflect on your app.
The height of the scrollview depends on it's content, so you need to add elements from the top down so it gets bigger.

What are the correct constraints on UIScrollView from Interface Builder? Pure Autolayout from IB

I have been trying to get ScrollView to work for 2 days now, and it doesn't work at all. Most of the suggestions here on SO and other websites say that you need to pin the ScrollView to the root view and then place a ContentView (UIView) inside ScrollView and then pin it to all sides of the ScrollView (so that the scroll size can determine the contentSize... However this does nothing). There's also conflicting information out there, one video says that there needs to be a constraint from the bottom of the ScrollView to the ContentView. Neither solution has worked for me. Here is what I've been doing in most of the combinations I've tried:
UIView -> UIScrollView
Pin all sides of the UIScrollView to the UIView
Create a UIView (name it content view) and place it inside UIScrollView
Pin all sides of the UIView to the UIScrollView
Problem at this point: UIScrollView needs constraints for X or width AND Y or width. The only thing that seems to solve the complaint is setting the UIView inside the scroll view centered horizontally and vertically, but this does nothing to make scrolling work. Another option is setting the UIView equal height and width to scroll view, but again, that does nothing other than remove the complaint.
I don't understand. Isn't pinning the sides, setting the constraints? IB seems to think that this is not the case.
What are the correct constraints needed? All I need is a simple view with stacked controls (to fill out a form) and the screen needs to be able to scroll if the form is longer than the screen.
I'm using iOS for the first time, and building purely from IB for now... minimal code solution would be best.
You are half way there. First you need to decide what you are going to display in the scrollview, you have placed a content view, that needs to have an intrinsic size. You can choose to put there static or dynamic views. Static views will have their size defined at design time, and that will resolve the UIScrollView AutoLayout constraints. If instead you are doing it at runtime with dynamic views you will need to choose a default size for your content view, create an IBOutlet for the width and/or height of your views and then resize them at runtime altering the outlet in viewDidLayoutSubviews. The video you linked explains that quite clearly.

UIButton under UIScrollView not responding to touch

I am facing a very strange problem. Trying to implement constraints to my view controller makes my button inactive.
My view hierarchy is
UIVIew
UISCrollView
UIView
UIView
UIButton
There are many other views but just for simplicity. One thing is that there is an UIImageView object, which I am stretching to the view according to size but not objects are overlapping or similar, but might be related.
Basically all the constraints are in storyboard. Only for the image view I am using manual setting.
self.imageViewHeight.constant=imgHeight;
when I disable auto layout the button works just fine.
EDIT: Latest observation :Just found out that simulator iPhone 6+ works fine with the constraints. The same is happening with a similar view, which is smaller so all iPhone works just 4S.
So it is definitely issue related to screen size and manipulating with constraints.
Looks like all objects that are bellow screen view itself after creation, so you have to scroll it to see them are inactive.
Any help will be greatly appreciated.
It seems you need to increase the frame Width or Height (whatever you need) of container view. The contentSize of scrollView only affects how it will scroll, which is irrelevant here.
If the button is outside the container view, it will still show up. However, it can't respond to any touch event.
HERE WHAT WE NEED TO DO FOR TOUCH RESPONSE
All you need to do is set bunch of constraints for CONTAINER VIEW of scrollview. Start from adding leading, trailing, bottom, top, width equal and height equal. Now in my case, I need fixed contentSize of Scrollview, so i change priority of equal width constraints to 750. For dynamic contentSize, you need to set priority programmatically.
Comment below if you have any query..
Thanks

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.

Why is AutoLayout not taking care of my UICollectionView

I have built a very simple sample of an app (Source code on github) using a UICollectionView.
Everything is working fine, as long as the app is in portrait mode. When it is changed to landscape mode however, the content cell is not resized appropriately, and thus, nothing is displayed.
I thought that all the necessary AutoLayout constraints are in place. I am aware that I can implement collectionView:layout:sizeForItemAtIndexPath:, but my goal is to use AutoLayout as much as possible (simply to understand AutoLayout better).
What am I missing here?
You can use autolayout to set the position and size of the collection view. And you can use autolayout to set the position and size of the subviews inside each cell. But you cannot use autolayout to control the position and size of the cells. You must use the collection view's layout object to set the position and size of each collection view cell. If you want the cells to change size when the interface orientation changes, you must update your layout object to report the new size and invalidate the layout.

Resources