Working with UIScrollViews - ios

I've watched many Youtube videos on UIScrollView. Here, here and here. However nothing there is solving my issue.
Here I've a sample storyboard that I'm working with.
What I require:
The ViewController must be embedded in a Navigation Controller.
BlueView and CyanView will adjust its height accordingly to screen size based on aspect ratio.
YellowView will have a variable height as it contains a ContainerView with embedded UITableView or UICollectionView. Meaning my users can switch between views to look at similar data, with different format. Its information is grabbed from server side. This means that if there is no content, it doesn't require any scrolling. If there are many rows of data to fetch, scrolling should work to display all my information.
Problem faced
If I do not set specific heights to each of my views, IB will complain about the need for constraints on height or Y position.
When I try specifying the height in IB (so as to avoid the complain), during runtime, I attempt to change the height of my yellowView and myScrollView, the scrolling doesn't happen at all.

Inside the UIScrollView add a container View. That will contain rest of your views. So the heirarchy becomes like this:
|---UIScrollView
|----UIView
|---Blue View
|---Cyan View
|---Yellow View
This container view will have a leading, trailing and bottom and top to the UIScrollView. Also add a equal width and equal height constraint to your UIViewControllers main view. Give a priority of 250 to the equal height constraint. And then:
To the blue view, add a leading, trailing and top constraint to its superView and add the aspect ratio constraint. Tinker with the values till you see a UIView which looks nice to you.
To the cyan view, add a leading and trailing to its superView and add a top spacing to the blue view. Add the same aspect ratio as the blue view.
Now for your yellow view, add a top to the cyan view, and leading, trailing and bottom spacing to its superView.
Now your UITableView will have a leading, trailing, bottom and top to the container view or just directly use a UITableView.
If you wish to embed a UITableView inside the yellow view or just use a UITableView directly and expect the main UIScrollView to be scrollable, you will have to manually get a height constraint outlet for your UITableView and update it accordingly depending on the number of rows of the UITableView and height of each row so that the yellow view can increase its height based on the height of the embedded UITableView and hence update the content view accordingly which will in turn update the total content size of the UIScrollView.

Related

Scrollview in storyboard does not scroll

I created a scrollview in storyboard with multiple views but the scrollview does not scroll. See the screenshot. I have a scrollview with images and another view embedded that spans outside the view area. I would like the scroll view to scroll down but it does not when I see the code in the simulator.
You need to add a UIView with 1000(or whatever you want) height constant to scrollView and make the UIView equal width to view
ScrollView needs to know its scrollable area, so you need to provide information about width and height for ScrollView's content:
width - you can create empty view (with height constraint equal to 1), place it inside scrollView, set its leading and trailing constraints to scrollView and set width constraint equal to main view. Then, scrollView will know that its scrollable area has the same width as screen.
height - you need to provide top and bottom constraints for first and last components inside scrollView (and all components should have specified height). I guess you forgot about setting bottom constraint for the last item.

UIScrollView with Content View

I've been trying to create a UIScrollView for user registry but with no success. I'm using auto layout and all of the fields that go inside the scroll view are static. Because of the usual ambiguous height issue, I've added a UIView inside the scroll view, set the constraints to the margins of the scroll view and centered aligned it. After that I added all of the fields inside that Content View, in the storyboard.
The content fields have their constraints setup as you would expect, but when I get to the lowest field and set the bottom constraint to the bottom of the Content View then everything breaks.
I'm asked by Xcode to set the priority of some views, and when I do as is says, the Content View size stays the same and the views are shrunken.
I tried not to put the last bottom constraint and resize the Content View by code but the height is not resized as is should.
I'm looking for a good solution to do this in storyboards and auto layout.
Update: I added a bottom constraint with a low priority, but the content scroll view is not expanding to show all of the fields.
Add&Set ScrollView(UIScrollView)
Add&Set ContentView(UIView) with subviews
! Set ContentView Width equal to View Width
Set all subviews constraints
View1 should be tied to the top of the ContentView
View4 should be tied to the bottom of the ContentView
All SubView (View1, View2, View3, View4 ...) must have a height and distance between each other
P.s. In your case, if iOS > 9.0 you can replace ContentView with UIStackView
You are using auto layout so the size of the content view is determined by constraints. Follow the below steps to provide proper constraints:
Drag the Scroll View inside main view and provide constraints Top, Bottom, Leading and Trailing in align with Super View (Main View) as
per screenshot.
Take View which will contain your content and drag inside Scroll View. and provide the constraints Center X, Center Y, Top, Bottom,
Leading and Trailing in align with Scroll View as per screenshot
Put all the element inside content view which is a subview of scroll view and provide Top constraint relative to the element above
it, to make equal space between the elements (eg. label, button etc.)
(Make sure you provide required constraint for X-position)
Last element is "Register Account" button make sure you provide the Top Constraint relative to country and Bottom constraint relative to
superview (content view) and change the priority for Top or Bottom
constraint as per screenshot, otherwise it gives error.

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 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