Cocoa-Touch: How to do layouting - iphone

I have a view (UIScrollView), which loads some data, and displays various things from it in various subviews. So I have approx 10 subviews (UIImageView, UILabel) and I need to place them programatically considering their unpredictable contents (i.e. different height/width for the UILabels depending on the text property).
From what I've read, there is no layout framework for Cocoa-touch.
What is the best way to do this?
From what I can tell, I should put the contents in the views, then start calculating coordinates based on their frames after calling their sizeToFit methods.
This approach is very error-prone. Is there really no other way?

You are right, there are no automatic layout managers. Subclassing UIScrollView and overriding layoutSubviews is probably the right way to implement your custom algorithm. You can then call setNeedsLayout to do the layout.

Layout in Cocoa is typically done with auto-resizing (using autoresizingMask). You start with your view at some hard-coded initial size, say 200x200; place your subviews onto this view and set the autoresizing flags accordingly. This view is then free to be resized to its actual size, as determined by its parent view/window. The process is the same whether you use Interface Builder or whether you do it programmatically.
If you need a vertical stack of views you can use a table view.
If you want more complicated layout you need to implement it yourself, by overriding layoutSubviews.

I'm not aware of any automatic layout managers or the like.
So, I think you'll have to calculate the desired positions and sizes and update the frames of your subviews manually.
EDIT: I found this question where Brad Larson points to an example of a custom layout manager. HTH

You can use Interface Builder to create a view and then drag and drop elements into it.

Related

Where is the right place to customise your view?

I was thinking of either viewDidLoad or inside my view subclass in awakeFromNib (since I load the view from nib). From the design point of view, encapsulating the customisation inside the view subclass sounds better. What are other options?
For me:
If the UI changes require coordination with the app's model, I generally do it in the view controller as I like to think of that as the gatekeeper between the model and the view. If it's creation of controls, I may do it in viewDidLoad, sometimes viewDidAppear. If it's re-layout of stuff based upon orientation changes, I'll do it in viewWillLayoutSubviews.
For anything of complexity that does not require extensive interaction with the model, I'll do in the view subclass.
The obvious other alternative it to design it in Interface Builder (with the appropriate autosizing masks and/or autolayout constraints) so you don't need to do anything programmatically. Often people are doing layout changes based upon orientation or size of the control that could have been taken care of automatically through judicious autosizing settings or autolayout constraints. Clearly this is often not possible, but don't overlook these if you're just adjusting layout based upon the size of the main view.

Automatically reposition views after UITextview resizes - iOS

For a simple example lets say I have a UITextView with a Button underneath it. These two controls are siblings both embedded in a parent UIView.
I now change the text within the UITextView and resize it accordingly. Is there a way to make the button automatically move to have the same relative distance to the bottom of the UITextView? This may seem trivial for this case, but I will have a longer hierarchy with multiple UITextViews that change and it would be nice not to have to calculate the height of every object manually.
One way to approach this would be with a table view: if you place each of your text views within its own table view cell, the table view will automatically calculate its total height from individual calls to its delegate’s -tableView:heightForRowAtIndexPath: method and lay itself out accordingly. Whenever the height of one of your text views needs to change, you can call -reloadData on the table view to make it lay itself out again. A disadvantage of this approach is that it’s really difficult to animate the height changes; if that’s essential to the effect you’re going for, I’m afraid you’re stuck with doing the entire layout manually.
Try the autoresizingMask property of UIView.

How to stack/z-position multiple UIElements (uilabel, uiimageview, etc) on top of each other?

I've got several UI elements on my screen (programmatically) and am in need of an efficient way to give each subview a z-index setting, so I can stack certain elements over others.
Does anyone have a solution to this?
The plain -addSubview: method will add the new view on top of its siblings.
There are also a bunch of methods like bringSubviewToFront:, insertSubview:belowSubview:, etc. that you can use to manipulate the ordering, listed under "Managing the View Hierarchy" in the UIView Reference

How to arrange labels in a flowlayout manner?

How do I arrange some UILabels and/or UIButtons of a variable length? I just want to add them to a UITableViewCell and they should arrange in a left-to-right flow, much like lines of text in a paragraph.
I only found possibilities to create lables with a fixed size and position using "initWithFrame:...". Same seems to be true for Interface Builder, as far as I can tell. Any solution is appreciated no matter if it's done in code or using a custom cell XIB-file.
UITableViewCell, UILabel, and UIButton are all subclasses of UIView and the documentation for UIView says:
Layout and subview management
A view may contain zero or more subviews.
Each view defines its own default resizing behavior in relation to its parent view.
A view can manually change the size and position of its subviews as needed.
So, it is certainly possible to do.
You can create your labels and buttons using initWithFrame: with the argument CGRectZero and then resize them (based on the text or whatever) using setBounds: or setFrame: (because right now you're just going to set the size of the view). Then, add these views as subviews of the cell's contentView.
Then, in a custom subclass of UITableViewCell you can implement your solution by overriding the default behavior (which does nothing) of layoutSubviews: to set the origin field of the subview's frames (i.e., CGRect) that will position the subviews in the cell's content view (the size has already been set). You may need to call setNeedsLayout: or layoutIfNeeded:.
This is really a rough outline of how it is possible to implement a solution because there are a lot of details left out. For example, if you resize a button based on the the text of the titleLabel you'll probably want to pad some to the width and height otherwise the button will be the size of the label and will look odd. In the layoutSubviews: method there could be a fair amount of logic to layout the labels and buttons the way you want (e.g., it would be simpler if all the subviews of a cell where of the same type such as all labels) esp. if the subviews could wrap to a new line.
For multiline UILabels to get the width and height you should use the NSString method sizeWithFont:constrainedToSize:lineBreakMode: you can then use the sizes you get to lay everything out where it needs to be.
I want to do the same thing to allow users to enter tags into a text field - a bit like how when you type in an email address, the address gets converted into a blue tag (the the users name in when that users email address is already in your contacts list). Haven't written it yet, but will be happy to share with you once I do. I can't commit to how long it I will take to write this unfortunately. However if no one else has code they can share and you need to get the job done quickly - Just as a tip, consider this:
Create tag view objects where each object knows the size of the parent text field/tag container view and where each tag object has a utility method which a further tag object can use to insert itself at the right position. This approach makes it easy to manage the view and relayout tags using a simple iteration flow.
Hi
If you still need an answer...
To get the size of text (and to then calculate the frame of the UILabel/UIButton etc) use the sizeWithFont: NSString function which will give you the width/height of a string of text using a specified font.
There is a little bit of maths that you'll need to do to work out the best fit, where to place the UILabels, and the spacing, but you will have the data that you need to do it.
Hope this helps!

iPhone - Make loadView entries fill up parent view?

I have a loadView call that basically places one view at the top (like a header) and one at the bottom (like a footer). It's possible via a passed in parameter to not have a header or a footer, to hide them later, or to resize the view. I have all this working, but it's very susceptible to breaking because the views can go in various places of various sizes and all must be manually set to the correct size or they will not use up all the space. I want one in between the two of them that automatically resizes to fill whatever space is not taken by the others.
loadView doesn't seem to be able to obtain the size of its parent's frame (or where it's being fit in, exactly), nor do I see an obvious way to just put the center view at a certain position and have its width and height automatically adapted.
Any ideas?
If I'm not explaining myself well enough and you know Java Swing, think BorderLayout with a BorderLayout.NORTH, BorderLayout.SOUTH, and BorderLayout.CENTER component.
loadView isn't a good place for this. You really want to use viewWillAppear instead. Setting autoresizeMask to have fixed borders should do what you want without having to worry about calculating layout, and it's best to do this all in IB rather than doing manual layout all the time.