I'm quite new to iOS, specially to complex views using Storyboards. I've started to develop the following screen trying to use AutoLayout so I don't need to worry about different iDevices screen sizes.
I'm using ScrollView to move the content to visible space while need to input some info with the keyboard. The thing is I re-created all the constraints a lot of times trying to make the fields respect the width of the ScrollView. Actually, when running, all the fields are being displayed larger than the ScrollView width (it's like overflowing the screen width to the right). The curious thing is that the button respects its width. When I change the orientation to landscape on iPhone 6s Plus those fields has smaller width than the screen width as if I had defined a specific size and the button continue to respect the size according to it constraints. Any thoughts?
Hierarchy:
View Controller
View A
Scroll View
View B
Logo / App name / UITextFields / Switch / Button / Link
Basically the Scroll is constrained with View A. View B is constrained by equal width with to View A and to Scroll margins.
Current Xcode version: 7.2 (7C68)
Please find the constraints added to scrollview i.e top,left,right,bottom constraints.
At the same way set constraints for individual elements inside scrollview i.e textfield and button. For these elements , set left,right,top and height constraints. I have added in my code to achieve your functionality see screenshot below.
Scroll view constraint - top,bottom,leading,trailing ,
View B constraint - top,bottom,leading,trailing and must height-width constraint set ,
Other element - leading, centrally vertical and must height-width ratio
please try, this will help to solve your issue.
First I would like to thanks Bharath and Dhaval for their answers, they were really helpful.
Although the answers helped me to have a better behavior in this view, it turned out that my problem weren't related to the ScrollView but with a mask I'm applying to those fields and the moment where those mask were applied.
I was applying these mask to get a customized round corner so I had the corners exactly like the post image:
// Change webservice's text field style
CAShapeLayer *shape = [[CAShapeLayer alloc] initWithLayer:self.url.layer.mask];
UIBezierPath *shadow = [UIBezierPath bezierPathWithRoundedRect:self.url.bounds byRoundingCorners:(UIRectCornerAllCorners) cornerRadii:CGSizeMake(5, 5)];
shape.path = shadow.CGPath;
self.url.layer.mask = shape;
But this mask were applied in viewDidLoad. Changing to viewDidLayoutSubviews solved my problem and I get the right design and behavior in portrait or landscape: round corners where they should be round and respecting the constraints.
Two other sources from stackoverflow I didn't found before and may be useful for people having problem with ScrollView:
https://stackoverflow.com/questions/31015026/autolayout-and-uiscrollview-storyboard-constraints-are-not-respected
UIScrollView Scrollable Content Size Ambiguity
Related
I try to auto-resize my view with auto-layout contraints, but I have some errors of Y-position missing. I can't understand what is wrong, I attached my Y-position to the top of the view.
Thanks for your help, here is the screenshot:
The problem is that you don't set a fixed height but, if you can, ALWAYS AVOID to put a fixed height for a view. For an app that can fit all screen is better to use different techniques.
If don't want to set a fixed height on your view, you have two possible options:
Give to the view a bottom constraint. You should also set the distance between the bottom of your view and the screen (or another object below your view).
Use stackview. If you place your views into a stack view you will be able to autoresize the width and height of your views according to the screen dimension.
You must give a height for the view or construct it's subviews in a way that gives it a height by hooking constraints properly from top to bottom
when you have a y position error it means top, bottom and height issue
and when x it means leading , trailing and width issue
IF you want to create dynamic view drag a vertical UIStackView and give it a height and in runtime add items to it
self.myStackView.addArrangedSubview(lbl)
I am making a note taking app in xcode8 for iOS 10.2. The note is consist of a textfield, textview and imageview. I am adding textview and imageview in separate scrollviews (to provide the facility of zooming and adjusting image). Then I have added both scroll views in a stackview to ensure that imageview and textview stands side by side in a landscape mode. To do that, I have added variation to axis property of stackview( width=any, height= compact and Gamut=any, and set that to the horizontal, as shown in right corner of screenshot to see view hierarchy without any constraints).
I have tried many constraints but, every time it fails to adopt. Let's take an example, I am adjusting size of the scrollviews on the size of content(by setting top,bottom,leading and trailing constraint), the stack view is adjusted to the main view. Now, the only thing that needs to be adjusted is text view and imageview with respect of stack view. But, here is the tricky part If I include a fixed trailing constraint of text view to the stack view; it will work in portrait mode.As soon I turn into landscape mode that constraint will not work(the trailing constraint which have 0 distance from stackview) because the edge will be side to the imageview not to the stackview(because I am putting image and text side by side as explained above) which will make textview larger than required, same goes for imageview's leading constraint to the stack view and vertical distance constraint betweem image view and textview.I think the root of the problem is I have made a variation to the axis of a stack view (in order to get text and image side by side in landscape mode) but, that was necessary part.Can anyone have solution for this? Do you think there can be other problem? Should I choose Intrinsic Size of scrollviews to placeholder option or let it be system default?
Thank you.
So I hope I understand the question and I will try to walk you through what I understand you hope to accomplish. I preface this by saying I just started using UIStackView because of backwards compatibility.
Note. To get the magic of ScrollView with AutoLayout I almost always embed them in another UIView. There are reasons to not but in this case you will see how valuable this is to AutoLayout.
Step 1) Drag your UIStackView and add Top,Bottom,Leading, and Trailing. Now add 2 UIViews and set the UIStackView to Fill Equally. It will now look like the image(Background colors to check your work).
Step 2) Now add a UIScrollView to each of these UIViews. Add Leading,Trailing,Top,and Bottom on each of these.
Step 3) Add a UITextView and UIImageView to the ScrollViews respectively. Now Autolayout is mad at us :( but we will fix that.
Step 4) Drag from the UIImageView to the View that is holding the UIScrollView(First Set of Views we added). See image
-Choose the option to add Equal Widths. See Image
Repeat the same step but add Equal Heights. Now add Top, Bottom, Leading, and Trailing to the ScrollView.
Step 5) Repeat exact Step 4 with UITextView
Your final view hierarchy should look like this.
Now you can rotate your UIStackView and do what you want I think.
And Horizontal
Side by Side Preview
I did add a <= 0.1 equal heights multiplier on the textfield at the top but I don't know if that was necessary.
Enjoy.
I have a UIView buttonView and gave it an equal heights constraint to the super UIView with a 0.4 multiplier. The frame is adjusted correctly but the subviews of buttonView are not visible. However, when I click on the position where the buttons are supposed to be then the actions triggers.
This does not happen when I change the buttonViews constraint to be a fixed height.
I can get more into details if you want but has anyone run into something similar?
EDIT
There should be two buttons where the white space underneath the label is. When I click on the white space the timer runs but the button is not visible.
I took a look at the project and the issue I saw in a couple places was that auto layout and manual frame transformations are both used, which can be tricky. A couple specific things I saw that you will probably need to modify in order for the view to adapt and render correctly at different sizes / orientations:
1) The CustomAudioLearn view loads a view from a xib and adds it as a subview. However, it does not set constraints on this subview to make sure that the subview always hugs the edges of the parent view. So changing the size of the CustomAudioLearn view through auto layout in the storyboard results in the the xib-based subview always staying the same size. You should either add constraints to the subview or override layoutSubviews() in CustomAudioLearn and include self.customView.frame = self.bounds and self.customViw.layoutIfNeeded() in there. Also, I would suggest removing the line self.customView.translatesAutoresizingMaskIntoConstraints = false
2) Similarly, the RecordButtonView sets its corner radius on awakeFromNib(), but after layout happens, that's no longer the right radius. So you should again consider overriding layoutSubviews() or similar location to adjust the radius every time the layout is updated.
3) Lastly, the superview of the RecordButtonView in the storyboard is set to a height constraint of 70 with a priority of 1000. If you want the RecordButtonView to expand for the space available, you should reduce the priority of that height constraint so that the proportional width of the RecrodButtonView and the 1:1 aspect ratio take priority in determining the height of the superview. Otherwise, it will always be 70 points, or there will be conflicting constraints.
The problem was that I set the rounded corners to half of my frame's width. The radius got so big that it completely hide the view. I changed it so that after the bounds are set I change the corner radius. Sorry for confusion but thanks for any help!
I have been struggling for days with this implementation, and even though I have tried to do every tutorial I found on the web, I still cannot make things work the way I want.
Basically, I am trying to put my login form in a scrollview, so that it takes the whole screen at first (and on all iPhones / iPads), and if the keyboard appears everything should move. The problem IS, my view doesn't take the whole screen... Either it is too large, or too high, even though in Interface Builder everything seams correct (from layout to constraints). Below and image of the layout I want to achieve (I am using an universal storyboard, with Size Classes and Autolayout enabled):
http://img4.hostingpics.net/pics/829115app.png
Can someone point me out on achieving this layout ?
Thanks in advance.
I would suggest pinning top, leading and trailing spaces of your scroll view to its superview. And set a bottom space constraint less or equal to the keyboard's height if you set it to 0, the scroll view won't be able to resize.
With your form layout set vertical center constraints and top space to superview constraints for your top label being more or equal than the distance you set in the IB, and then you can set relative space constraints between each of the components.
Hope I answered your question.
Edit: Just the provided project and got it working. I think the problem is caused by it being a containerView inside a scrollView. And both the container and the scrollViews content view adapt to the size of its subviews. Because of that, setting relative constraints won't help.
What I did was to set an explicit size (screen's size) to the containerView and setting setTranslatesAutoresizingMaskIntoConstraints(true) to it.
I modified your project and uploaded it here
I'm developing an app targetting iOS6/7, and I've lost two hours staring at a storyboard, trying to understand why autolayout doesn't do what I want it to do.
Basically, I have a scene containing a scroll view and in it, I want to have a UIIMage anchored at the bottom right. Therefore, I set four constraints for the image:
Width equals
Height equals
Bottom space to superview and
Trailing space to superview
XCode does not complain about the positioning, so I run my app with confidence, only to find that it is not shown in any orientation. It's just nowhere to be found!
I know that to find how autolayout implemented the constraints and did its magic, I have to inspect the view.bounds rect. I checked at the viewDidAppear event, to find its value to be as expected though:
Image pos is: 0.000000,0.000000 106.000000x103.000000
The frame is of course at the actual position in the storyboard which I guess is to be expected.
Here is a screen cap of my Storyboard:
Any ideas?
Update:
Some more info:
If I remove all constraints and run the app, the image view is shown at the bottom right of my view in portrait, but when rotating, as expected, it is not shown.
Update 2:
This all should fall in the dreaded UIScrollView and AutoLayout threads. In the end I reverted to using a UIView, inside of which is a UIScrollView containing all the content I wanted to scroll (so that no text fields are hidden by the keyboard in landscape mode). The image I wanted anchored at the bottom was left at the container UIView and it all worked as intended.
If you want to anchor to bottom right, Programmatic autoresizingMask has been far more consistent for me.
It's slightly opposite of IB so if you want to anchor bottom right, you want the left margin flexible and the top margin flexible
yourView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
This means that bottom margin, right margin, height and width will all remain the same, keeping it in the lower right of your view.