Where is the right place to customise your view? - iphone

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.

Related

Which design approach should I take for creating this custom view?

I'm trying to create a generic, reusable view, that looks like a lined notepad. The way I decided to approach the problem (after a couple design iterations) is to create a custom view that is composed of a UITextView and a UIView.
When the user scrolls through lines of text I want the UIView to track the scroll direction. The key here is: Within my custom view, I need to change the position of one subview in response to events in another subview. Something needs to coordinate these changes...
Now, one approach I thought of taking was to use a MVC design pattern. A view controller could handle all events and move the subviews around accordingly. This MVC could then be embedded in other MVCs.
Normally when using a MVC design pattern, a controller would handle user events and manipulate the model and view. However, my custom view doesn't have a model - all I'm trying to do is have the view manage it's own subviews when a user does something like scroll. It seems to me that the MVC design pattern isn't a good fit here for two reasons:
There isn't a model or logic that is specific to the program it's being used in.
It seems to me that the view should be responsible for handling user events that change how the view should appear.
... but I could be wrong, which is why I'm asking for help. The question, for those who are more experienced than I and who may have done this many times before, is:
What type of design pattern is appropriate in this situation? MVC or...
You want a view to manage its own subviews? Then do that! So what if that pattern doesn't have a TLA?
A typical approach is to implement layoutSubviews in your container view. Have it check its current state, or the state of the other views in the window (e.g. the contentOffset of a scroll view), and then set up its subviews appropriately. (Resize them, reposition them, etc.)
Just try to keep it fast, since it's likely that layoutSubviews will be called frequently.

When in the view reload resources when orientation changes?

I have view that have many subviews, and each have it's own graphics, different for portrait and landscape orientations. When should I load the new graphics when the orientation changes?
If shouldn't be layoutSubviews, I don't also like the idea of reloading resources in view from UIViewController, because of complicated view hierarchy that I have (it would require to pass this information down).
There is also option to register in NSNotificationCenter for orientation changes in each view, and load new resources when it changes. But I don't quite like it either, because I believe that there should be mechanism in iOS that enables that. Or, maybe I should think in a different way, and build different views for portrait and landscape...
What do you suggest?
I would have your subviews all extend a custom view class that has a -setOrientation: method that swaps between the portrait and landscape graphics. Then in your view controller I would override -willRotateToInterfaceOrientation:duration: and add a loop that sets the orientation for all of the children, thereby causing the graphics to swap when the orientation changes.
I think that's the most straighforward way to do it. Using NSNotificationCenter could be tricky and you're left without a guarantee that every child will get the notification.
Anyway, that's how I'd do it. Let me know if you need examples.

How do i make orientation work in my app?

The way my app currently deals with orientation is it repositions all of the items in the view, the layout of which can change as the user interacts with it. I've had numerous problems, such as view's not appearing, views changing before the screen rotates etc. I'm wondering the best way to deal with orientation?
If the landscape-layout is completely different from the portrait-layout I just load all subviews in the init-method of my UIView-subclass and added them as subviews.
The whole magic is done in the layoutSubviews-method where I only check in which orientation I am at that moment. Never call alloc, addSubview, removeFromSuperview, ... methods in layoutSubviews. The layoutSubviews should only contain code that sets the frame-properties of subviews.
Referring to your problems:
view not appearing: maybe forgot an addSubview-call
views changing before the screen rotates: you probably update some frame-properties of subviews outside the layoutSubviews-method
One possibility - if your app only works with one orientation, disallow orientation changes. This is a reasonable response, some apps are only usable in one view.

Interface Builder - Accurate Layout

I am working on a GUI in Interface Builder for an iPhone app.
In my view controller, I would like to have a toolbar at the top and then some controls (i.e. a view) that are centralized in the lower portion of the view.
The problem that I am having is that I want things to be centralized in the area below the toolbar but the whole screen size (including the toolbar) is being used when centralizing.
Any ideas how to effectively achieve this type of layout - it must be pretty common but I haven't found anything yet.
Thanks,
Alan
You might want to try putting all your control area below the toolbar in a separate subview, since that subview might do what you want as it resizes.

Cocoa-Touch: How to do layouting

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.