How to handle relative positioning in iOS automatically? - ios

I want to position a sub UIView (sub_UIView) as a subview of parent UIView (parent_UIView). When the parent_UIView resizing/moving, the sub_UIView would stay the relative position of the parent_UIView. For example, the sub_UIView is at the bottom right corner of the parent_UIView. When the parent_UIView is moving, the sub_UIView would stay at the bottom right corner of the parent_UIView automatically.
I managed to do this manually by updating the frame of the sub_UIView when the parent_UIView's frame moving, but how to do this automatically in iOS? are there any properties for this? (similar to autoresizingmask for resizing subviews)

Updated old response, that only mentioned resizing masks
Autolayout (iOS 6)
In iOS 6, autolayout was added, albeit, kinda ugly to work with XCode in a storyboard/xib. Autolayout is way too big to explain, but the essence of it, is that it's a set of rules between views within the hierarchy. Thus, you can stick the x position of a view to the right border of a parent view. See the Auto Layout Programming Guide
Autoresizing Masks (iOS 2)
Take a look at the options in the Size Inspector:
This is the equivalent of doing
myView.autoresizingMask = UIViewAutoresizingMaskFlexibleTopMargin |
UIViewAutoresizingMaskFlexibleLeftMargin |
UIViewAutoresizingMaskFlexibleWidth |
UIViewAutoresizingMaskFlexibleHeight;
Notice that there's a difference between doing it by code and doing it through IB. The IB autoresizing settings for the borders work as struts, selecting the right one, for example, means, "my right border is now stuck to the superview's right border".
On the other hand, code does the opposite, where you need to specify which borders are not strut-ed, aka. they are flexible. Height and Width works normally.
Layout Subviews (iOS 2, but gotchas for iOS5+)
If everything fails, don't start doing manual positioning all over the place, I've been in that position, and it just leads to unmaintanable, spaghetti code, where three or more methods are messing with the same view properties.
Instead, prefer to do all your custom positioning on UIView -layoutSubviews. This method gets called as needed when a setNeedsLayout has been triggered, for example, when the width a view changes, the subviews get the layout subviews event. Also makes implementing rotating interfaces much easier, since this method gets called for the new width, to determine how the animation will look like.
Keep in mind that layout subviews works after Auto Layout/Auto-resizing masks have been performed.

Related

Constraints in ios

I am learning constraints and spent whole day applying them to the following screen.It is not getting displayed properly in landscape mode.Basically i am not getting how to fix vertical space between ,say, label-Welcome to BBBB and textfield-username so that textfield always appears below the label yet the spacing between them is adjusted according to the screens of different size. If i go for Pin\Vertical space, it automatically fixes the constant value.
Remove the label (or just move it out of the way).
Fill the space that you want to resize with a view.
Constrain this view to the objects above and below and to the sides of the parent view.
Put your label into this view and constrain it to the top of this view and centred to it.
You may need to change the constraints on the objects above and below it to stop them from changing height in an unwanted manner.
This new view should now resize as the device changes orientation but the label should remain at the top of it.
Repeat on other areas of your layout (i.e put things that are not moving around as you want them into sub views and constrain these views to resize accordingly). Experiment with using variable heights, fixed heigh constraints and 'equal heights with' constraints on the views that you add to get them to resize as you need.
Edit: but you have a lot of vertically stacked items in that view - you may never get them all to fit into a horizontal orientation. You may need to remove a few, or add a scroll view or force that view only to layout in portrait mode or... Don't forget to check that it works on all devices you are targeting.
#Ali Beadle was right. Since i had a lot of vertically stacked items, lining them up in landscape mode was not possible. So, i went for scrollview.
I have taken a ScrollView first and then a UIView named ContentView on that ScrollView. I have made the width of ContentView equal to the width of parent UIView and kept its height fixed to 568. In my code i set
_contentViewHeight.constant = self.view.frame.size.height;
Now it scrolls in landscape mode while in potrait mode, it does'nt scroll.
I run into Autolayout problems all the time. But I finally figured out a way to overcome a lot of issues that arise from it.
I simply will use a container-View like ScrollView or even a plain old UIView, place all my controls in it. thats it. this makes things a lot easier for autolayout to figure out the constraints. in your case you could just use a UIView.
-start off by removing all the constraints you have I would start by selecting each control in the XIB and see if it has width/height constraint, select it then press the delete key then at the bottom of the project explorer you'll see all the constraints that auto layout has select each one then delete. that should get rid of any complaints that auto-layout might have.
-Place a UIView object inside your main View then
-move all the controls inside it. Then
-add the necessary constraints for the container view so it'll resize in different orientations and don't worry about any constraints inside the container view (auto layout will figure them out automatically).
that does the trick for me usually.

UIView added with autolayout does not receive taps/events

When I add a subview with autolayout by settings its left, right, top, and height constraints, I cannot add a tap gesture and my buttons do not receive taps.
When I manually set the frame to the position I need and do not use autolayout, I can add gesture recognizers and my buttons are interactive.
Why would a view added with autolayout not respond to events?
I would like to use autolayout since I would like to respond to different orientations and sizes that are more complex than I would like to deal with with manual frame adjustment.
This can happen if you have restricted your view too much using autolayout. For example, you may have accidentally set the height of the view to zero or positioned it outside the area where you put your buttons. Note that the buttons themselves can be positioned in a place that appears correct when you look at them, but they are actually outside the area that the autolayout engine has calculated for the parent view.
Another thing that can hit you, is that if you added all your autolayout contraints programmatically, some contraints in the Interface Builder may still be enabled. You can make sure that IB contraints are ignored by setting view.translatesAutoresizingMaskIntoConstraints = NO;
Also, pay attention to any runtime autolayout warnings in the console window, they will often tell you if some contraints don't play well together.

How do I successfully use AutoLayout and Constraints in Xcode?

This is going to be difficult without the rep needed to post images... however...
I currently have a storyboard layout in Xcode.
I have a UIViewController which is split in two sections, the upper UIView, and the lower UITableView (For now, we can ignore this, however the same issue applies to the table view, and advice is also appreciated)
In the UIView, I have a ProgressView, which spans the entire width of the UIView, and is snapped to the padding distance from the edge of the view. The ProgressView is set to 50% and falls in the middle of the layout in the storyboard designer.
When this is simulated, the progress bar appears to be sitting well above 90%. Issue is, when the progress bar is shrunk (or the width changed in the storyboard layout editor) to about half the 'visible layout', the progress bar takes up 'most' of the simulated screen, and correctly displays the 50% progress.
I'm assuming this has something to do with the AutoLayout or Size Classes. I'd like to learn the use of this autolayout and constraints properly - as such, disabling either of these will not be acceptable. The suggested constraints are not returning my expected results.
Edit: I've figured out something that seems to work satisfactorily, see the given answer. But still keen to see some actual layout advice.
Edit: Applying the same principle to the UITableView in the lower half of the UIViewController and it also fixes the problems with Separator Insets.
I have found one solution.
In storyboard editor, open the document outline.
Hold rightclick and select the ProgressView and drag to the Parent UIView, release and select:
Leading Space to Container
Trailing Space to Container
Center Horizontally in Container
(Finishing here still has issues because the UIView exceeds the width of its parent still.... so do the same to the UIView)
In the document outline, hold right click on the UIView and drag to the Parent View, release and select:
- Leading Space to Container
- Trailing Space to Container
Now, I have a perfectly centered ProgressView with it sitting between the two edges and with the 'padding' on either end. Exactly what was required.
This issue seems to have spanned from utilising nested UIViews.

UIView not correctly applying autolayout to fill 100% width of parent

I am building an iOS interface in Storyboard. I have a custom view named LevelsView which inherits from UIView, which I want to fill the lower half of the screen. This custom view is the child of a parent UIViewController/UIView.
The two following images might help illustrate, where the green area is the LevelsView:
As you can see, I've added a leading space and a trailing space constraint to the superview, in an attempt to make it match the width of the superview, and hence the screen. However, at runtime the width doesn't ever change - it's always the width as it appears in storyboard (600px). How can I make the LevelsView fluidly fill 100% of its superview?
Two further notes of which I'm not sure have any impact:
Although I'm building a custom UIView-derived view, the same problem occurs when I use a plain old UIView in its place.
I'm building this app in Swift, though I'm not aware of any bugs that affect IB.
I apologise if this has been answered elsewhere - I can't find anything but it seems like it should be a common question.

iOS 6 Constraints Making the UIView Longer

I am not sure what is going on and how to handle this. I have a UIView in a cell and I set the constraints using IB and for some reason it stretches out to the end of the cell. How can I stop it from stretching.
And here is the result:
I am dynamically injecting a stepper control but as you can see the UIView stretches to the end of the cell. I tried pin width then it completely messes up everything and does not even display the UIView.
Here is the screenshot of constraints:
Okay, let me draw some distinctions here.
The trivial way to this is you always have the stepper in the cell (and no UIView). For those cells where we are not supposed to see the stepper, you set its hidden to YES; for those cells where we are supposed to see it, you set its hidden to NO. That is what I would do.
The programmer way to do this is you don't have any blue UIView in your cell at all. You add the stepper in code, and you also provide its constraints in code to position it. You said:
so I don't have to hardcode the coordinates
But adding constraints in code is not "hard coding" the coordinates. With constraints, you describe the position conceptually in terms of insets from the superview, and as the superview resizes, you are still correctly positioned. So there is no philosophical objection to adding the stepper and its constraints, and it is just laziness not to do that.
The lazy but wasteful way is to do what you are doing, i.e. add the blue UIView in the nib as a guide. Even if you do use the blue UIView as a guide, though, you should be able to get this right if your constraints are right. I just tried this and I was not able to reproduce the problem: my blue view appeared in my cells in the same place where it appears in Interface Builder.
The instant solution is don't use Autolayout in the nib from which a UITableViewCell is drawn — i.e. uncheck "Use autolayout" in the file inspector for this nib. You will thus use old-fashioned springs-and-struts (autoresizing) to position the subviews.

Resources