iOS - weird constraints using scrollview - ios

I have a weird behavior when I use scrollView.
As you can see in the picture bellow the button called "Back" has a bottom space constraint with value 0. But we can see is not even near to the bottom of the scroll view.
I already set the scrollview to have equals width and height of the superView and top,bottom,trailing and leading space with 0 value.
How can I fix this? I want the Back button still inside of the scrollview and put it at the bottom of the view.
Update
I have the code here https://github.com/rchampa/NDParallaxIntroView and the xib is called PageB.xib

Ricardo: you've added two constraint regarding manage y position of Validate Code button where your top constraint stop to move Validate Code button towards the bottom. So please remove top constraint of Validate Code only add bottom constraint.
you need to manage all constraint like your scrollview content view height will be equal to height. Please increase some top constraint from top.

So, if I understand correctly, the problem you are running into is that your back button is unable to be positioned based on the bottom of the scroll view.
A scroll has two sets of constraints in a storyboard, one that defines the size of the scroll view, and the other that defines the content size. The top, left, bottom, right to superview constraints on the scroll view will define the size.
The part that is causing your problem is that the content size is defined by the subviews inside the scroll view. So the button cannot be placed relative to the bottom of the scroll view since the scroll view doesn't know how large its content size is. All of the subviews of a scroll view must be placed in relation to each other.
So, create constraints for your logo, text fields, and all the buttons in relation to each other. Then create constraints from the outer most subviews to the scroll view.
In your example, you would constraints from the logo to the text field, 1st text field to 2nd text field, then 2nd text flied to the label, label to the "Send email..." button, and finally "Send email..." to the "Validate Code". For the "Back" button, it would need a left align with the text fields and then a center align with the "Validate Code" button. Create a top constraint from the logo to the scroll view. Then have leading and trailing constraints from one of the text fields to the scroll view. Finally, create a bottom constraint from either the "Back" or "Validate Code" buttons to the scroll view. You will also need some alignment constraints (logo center to the text field is an example of one). After that is all setup, your view will be fully defined for the content size of the scroll view.
If I understand you, my new question is: how can I make the subviews
make the height of scroll fit 100% screen device height? Is there a
way to define weights like Android? I don't know how achieve this
since the canvas is 600*600 which is different to every device.
Response would be too long for a comment:
So you wouldn't use a scroll view for that. A scroll view is specifically for containing content that will not fit on the screen (so the user can scroll to reach the new content).
The simplest solution is to add a regular view that has TopLeftBottomRight 0 distance constraints (so it is the max height and width of the screen) and setup the view like you have here to position the bottom in the bottom left all the time.
There is also a weight system, I can explain that if you want, but it wouldn't be required thus far.
I feel like your next response will be something like "what if I want it to scroll when its too small for the current screen?". The only way I know of doing that in encapsulating all your interface into a single UIView, and changing its sized in the viewDidLoad/viewDidAppear based on the size of the scroll view. Something like this:
func viewDidLoad() {
super.viewDidLoad()
containerViewHeightConstraint.constant = scrollView.frame.size.height
containerViewWidthConstraint.constant = scrollView.frame.size.width
}

Related

iOS UIScrollView, what am I misunderstanding? I cannot get a scrollview to scroll

I am a pretty new iOS developer and am coming across my first need for a scroll view. The page I need to design is a little complex. Since I was struggling to get that to layout correctly, I decided to create a super simple scene just so I could make sure I understood how to get UIScrollViews to work. Apparently it didn't help as things aren't working and I am stuck after following several tutorials.
I'm working in Xcode 8.1 and Swift 3.
Screenshots at the end of this post.
I have a scene that consists of a scrollview and a child view with two labels in it. I’ve set the labels to be ~700pt apart to try to make scrolling happen. Nothing scrolls and you can only see the first label. Additionally, the child view does not expand to be full height.
You can see in the screen shots that my scroll view has constraints to pin it to the sides of the superview.
The child view has the same.
The label constraints position them within the child view and 700pt from each other. I thought that this would give the views the height they need to make scrolling happen. There are no constraint errors.
I am hoping for the red childview to fill the vertical space and then scroll. At this point I’d take any layout as long as something was scrolling. Nothing is though, what do I not get?
Screenshots:
(removed due to link limit because I'm still a new SO user)
EDIT (6/12/16):
I've made some changes and gotten a little closer. Primarily, it was suggested to me elsewhere to set one of the labels to be equal height with the scroll view. This now gives me the "bounce" effect which means stuff is sort of scrolling; however, we're still only dealing with one screen of content as the second label which is hidden below is clipped off.
Here's where things stand:
edited hierarchy
edited screenshot
When you are using a UIScrollView in a storyboard, you need to ensure that the scroll view is able to compute the size of its content. If you don't have sufficient constraints then you will get an error in Interface Builder:
Scrollable Content Size Ambiguity
Clicking the Info icon on this error will advise you that there needs to be constraints touching all sides of the scroll view and to ensure that you can trace a continual line of constraints from left-to-right and top-to-bottom.
You can achieve this with or without the content view you have added. I will show you how to do it without the content view in scroll view, simply because there are fewer constraints that way and therefore less typing.
Add the scroll view to the root view
Constrain the top/left/top/bottom of the scroll view to its superview (the root view). Remember to turn off constrain to margins if you want the full width of the screen
Add label 1 and label 2 to the scroll view
Constrain top/leading/bottom of label 1 to the scroll view
Constrain top/trailing/bottom of label 2 to the scroll view
Constrain the trailing edge of label 1 to the leading edge of label 2 with 0 space
Constrain label 1 width to be equal to the width of the scroll view
Constrain label 1 height to be equal to the height of the scroll view
Constrain the width and height of label 2 to be equal to the width and height of label 1
There is no step 10 :)
ScrollViews are particular in that they like to know explicitly how much they are supposed to scroll. The best way I have found to handle this is to have the following hierarchy with some constraints:
-Scroll View
-Content View
-View (constrained to top, bottom, leading, trailing anchors)
-Your other views (e.g. Label)
By having one View living underneath the Content View and then containing all of your other Views within that View, the ScrollView then knows how much it's supposed to scroll (it just uses the size of the one child View) no matter how much stuff you have inside of the child View.
Let me see if I can snap a picture of an example from one of my projects. In the meantime, give this hierarchy a try and let me know if it works for you. You would probably constrain the Label to the top and leading anchors of the child View and then constrain the height to something taller than the screen (e.g. 1000 units).
Let me know if you have any questions.
Edit: Example hierarchy below

Add view under text view

I have a fullsceen textView including much strings, so height of this view automatically changes. Its works nice, but i need to create some newView under this textView.
If I just make constraints like bottom of screen = bottom of newView, top of newView = bottom of textView, so newView will overlap textView.
try add height constraints to your textView with priority is 750.
Now you can build your app and run it again!
Goodluck
Just add your text view to the new view.
Here you are adding view with same size of textview. So it will over lapping. But if you add your text view subview of view so your main view will go back and text view will come front.
I think the problem is your views are trying to fulfil their constraints on fixed screen size.
If you want to keep it on one page (no scrolling) you can either add height constraints to your text view such that its height won't go over certain value or set the bottom view's constraint priority higher so that even when the textview expand it won't overrule bottom view's constraint.
Otherwise you might want to add ScrollView underneath your views. This way when your textview expands the bottom view will get pushed to the bottom outside the screen and you can scroll down the page

Parallax header on a one-page screen in iOS using Interface Builder

In an iOS 8 app, I'm trying to create a screen that has a "parallax header", i.e., an image header that grows as you pull down. I would like to do this using only constraints in Interface Builder, if possible.
Here is a nice guide by Pete Hare on how to do such a thing, and I've also had good help at looking at this example project by Bill Carson. However, contrary to these projects, this is not the header to a scrolling area that's taller than the screen, like a Table View; it's just one page. And for some reason, I can't get things to work in my app. I find Scroll Views in Interface Builder rather confusing to begin with. Could anyone walk me through the steps?
Why, certainly! First we'll set up a view controller with a scroll view.
Create an empty View Controller. Give its initial View the Xcode Specific Label Root View so we can tell things apart.
Add a Scroll View. Resize it to fill the view controller, and add constraints for Leading, Trailing, Top and Bottom to equal the superview's corresponding edges. (I do this by control-dragging from Scroll View to View in the Document Outline, hold down the Option and Shift key and then select all four edges, and then Add Constraints.)
Enable Bounce Vertically in the Scroll View's Attribute Inspector.
Add a simple View to the Scroll View and pin its edges to its superview -- the Scroll View -- in the exact same way as we did with the Scroll View to Root View (although this time we don't need to hold Option key when adding constraints). Give the new view the Xcode Specific Label Scrolling Content.
Xcode is not happy, it says Scroll View is missing constraints: "needs constraints for X position or width" and "needs constraints for Y position or height". Let it automatically add missing constraints, it will add constraints for the center of Scrolling Content to the center of Scroll View, in X and Y directions.
By setting a background color to the Scrolling Content, we can now run and confirm that the scroll view with vertical bounce is working as intended. Nice. Now, let's add the header.
Add a nice header image to the project assets, and drag an Image View to the Scrolling Content. Label it Header Image. Select your image asset as the Header Image's image. Drag the corners of the Image View so that it is aligned to the top, left and right edges of your view. Now let's go through the constraints to set on the Image View.
We want the top edge to be fixed to the top of the screen, regardless of how the user is scrolling. So we need it to be pinned to something outside of the Scroll View. You may try fixing it to the Root View's top edge, but unfortunately, that does not work for some reason. What does work is to pin it to the Top Layout Guide. You'll do this easiest by control-dragging in the Document Outline, between the Header Image and the Top Layout Guide and accpet the suggested constant.
The bottom edge of the Header Image needs to be pinned to something inside the Scroll View. Ultimately, we'd like it to be set to a fixed distance from the top of the Scrolling Content -- but Interface Builder won't let us do that. You can only set it to some distance from the bottom of the Scrolling Content, which is not very practical since you will then have to take the height of the device into account. What we instead do is to add another view directly beneath the Header Image, pin that view's top edge to some distance from the Scrolling Content's top edge, and then pin the Header Image's bottom edge to our new view's top edge. This could be a regular View that holds the rest of your user interface below the header. But for this example (and to demonstrate a later point in this guide), we'll use a label. Add a label directly beneath Header Image and give it three constraints: pin it's top edge to the Header Image's bottom edge, it's top edge also to the Scrolling Content's top edge, and it's center X to the Scrolling Content's center X. The distance between the label's top edge and Scrolling Content's top edge will be the height of the image in the non-dragged state. This unfortunately needs to be set to a constant in the storyboard file -- we'll have to update it programmatically. More on that later.
The last part is easy: pin the leading and trailing edges of the Header Image to the leading and trailing edges of the Scrolling Content.
Now, all our constraints are in place! If you run the app, you can see how it's working correctly constraintwise, but the image isn't scaling the way we expect it to. A couple of last tweaks before we're done.
In the Attribute Inspector, under View, set the Mode of the Image View to "Aspect Fill". That gives it the correct parallaxy behavior.
To set the height of the Header Image correctly, we need a little bit of code. First, make an outlet from the constraint between the label's top edge and the Scrolling Content's top edge -- the one we set to a fixed value -- to your View Controller's source file. Call it imageHeightConstraint. Also add an outlet from the Image View called headerImageView. A good place to update the constraint programmatically is in the viewWillLayoutSubviews View Controller delegate method. Here is some code in Objective C:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
CGSize imageSize = self.headerImageView.image.size;
CGFloat heightForWidth = imageSize.height / imageSize.width;
CGRect screenBounds = [UIScreen mainScreen].bounds;
CGFloat screenWidth = CGRectGetWidth(screenBounds);
self.imageHeightConstraint.constant = screenWidth * heightForWidth;
}
Finally, you may notice that when scrolling up, the label -- or whatever content is underneath the header view -- is getting covered by it. This is solved by checking Clip Supbviews on the Image View's Attribute Inspector.
Whew!
(Note: I began writing this as a question and then kept writing while I solved it for myself. I guess it would do well with a little text pruning and some images, but maybe it will help someone...)

Autolayout in UIScrollView dynamic content with UIButton at bottom

I have to do a form in my application with dynamic content (it comes for a web service). So, I need a scroll for the case there are many textfields and there not fit in the screen. And under of all the textfields I need a button to save the info. My problem is that if there are few textfields (that fit in the screen) the button have to appear at bottom of the screen, and not under the last textfield.
I'm using autolayout programmaticaly to add the constraints of the textfields and add them in the view one under the previous one, but I don't know what constraints I have to set to the save button.
I have uploaded two images to explain that:
http://i.stack.imgur.com/KaPp0.png
In the first image I have only two textfields, that fit in the screen, so the screen not scroll and the save button appear at the bottom of the screen.
http://i.stack.imgur.com/SqVve.png
In this second image, there are many textfields, so the screen need to scroll and the save button will be under the textfields (at 20 pixels or something like that), and not at bottom at screen.
Do you can help me? Thanks for all.
Try adding below constraint to your save button -
1) Vertical space constraint to your last added UITextfield
2) Center horizontal constraint to your content view
3) Height and width constraint
Or
1) Bottom constraint to your content view
2) Center horizontal constraint to your content view
3) Height and width constraint
4) your last added textfield bottom constraint to Save button

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.

Resources