Creating and Managing the View Hierarchy IPHONE APPS

Managing the view hierarchy of your user interface is a crucial part of developing your application’s user interface. How you organize your views defines not only the way your application appears visually but also how your application responds to changes. The parent-child relationships in the view hierarchy help define the chain of objects that is responsible for handling touch events in your application. When the user rotates the device, parent-child relationships also help define how each view’s size and position are altered by changes to the user interface orientation.

Figure shows a simple example of how the layering of views creates a desired visual effect. In the case of the Clock application, tab-bar and navigation-bar views are mixed together with a custom view to implement the overall interface.

Layered views in the Clock application

Layered views in the Clock application

If you look at the object relationships for the views in the Clock application, you see that they look something like the relationships shown in “Changing the Layer of a View.” The window object acts as the root view for the application’s tab bar, navigation bar, and custom view.

View hierarchy for the Clock application

View hierarchy for the Clock application

There are several ways to build view hierarchies in iPhone applications, including graphically in Interface Builder and programmatically in your code. The following sections show you how to assemble your view hierarchies and, having done that, how to find views in the hierarchy and convert between different view coordinate systems.

Creating a View Object

The simplest way to create views is to use Interface Builder and load them from the resulting nib file. From Interface Builder’s graphical environment, you can drag new views out of the library and drop them onto a window or another view and build your view hierarchies quickly. Because Interface Builder uses live view objects, when you build your interface graphically you see exactly how it will appear when you load it at runtime. And there is no need to write tedious code to allocate and initialize each view in your view hierarchy.

If you prefer not to use Interface Builder and nib files to create your views, you can create them programmatically. To create a new view object, allocate memory for the view object and send that object an initWithFrame: message to initialize it. For example, to create a new instance of the UIView class, which you could use as a container for other views, you would use the following code:

The frame rectangle that you specify when you initialize the view represents the position and size of the view relative to its intended parent view. You must add views to a window or to another view to make them appear on the screen. When you do, UIKit uses the frame rectangle you specify to place the view inside its parent. For information on how to add views to your view hierarchy, see “Adding and Removing Subviews”

Adding and Removing Subviews

Interface Builder is the most convenient way to build view hierarchies because it lets you see exactly how those views will appear at runtime. It then saves the view objects and their hierarchical relationships in a nib file, which the system uses at runtime to recreate the objects and relationships in your application. When a nib file is loaded, the system automatically calls the UIView methods needed to recreate the view hierarchy.

If you prefer not to use Interface Builder and nib files to create your view hierarchies, you can create them programmatically instead. A view that has required subviews should create them in its own init With Frame: method to ensure that they are present and initialized with the view. Subviews that are part of your application design (and not required for the operation of your view) should be created outside of your view’s initialization code. In iPhone applications, the two most common places to create views and subviews programmatically are the application Did Finish Launching: method of your application delegate and the loadView method of your view controllers.

To manipulate views in the view hierarchy, you use the following methods:

  • To add a subview to a parent, call the addSubview: method of the parent view. This method adds the subview to the end of the parent’s list of subviews.
  • To insert a subview in the middle of the parent’s list of subviews, call any of the
    insertSubview:... methods of the parent view.
  • To reorder existing subviews inside their parent, call the bring Subview To Front: send Subview ToBack:, or exchange Subview At Index:
    with Subview At Index: methods of the parent view. Using these methods is faster than removing the subviews and reinserting them.
  • To remove a subview from its parent, call the remove From Superview method of the subview (not the parent view).

When adding subviews, the current frame rectangle of the subview is used as the initial position of that view inside its parent. You can change that position at any time by changing the frame property of the subview. Subviews whose frame lies outside of their parent’s visible bounds are not clipped by default. To enable clipping, you must set the clips To Bounds property of the parent view to YES.

Listing shows a sample application Did Finish Launching: method of an application delegate object. In this example, the application delegate creates its entire user interface programmatically at launch time. The interface consists of two generic UIView objects, which display primary colors. Each view is then embedded inside a window, which is also a subclass of UI View and can therefore act as a parent view. Because parents retain their subviews, this method releases the newly created views to prevent them from being overretained.

Creating a window with views

When you add a subview to a parent view, UIKit sends several messages to both the parent and child to let them know what is happening. You can override methods such as will Move To Superview: will Move To Window:, will Remove Subview: did Add Subview: did Move To Superview, and did Move To Window in your custom views to process changes before and after they occur and to update the state information in your view accordingly.

After you create a view hierarchy, you can use the superview property of a view to get its parent or the subviews property to get its children. You can also use the is Descendant Of View: method to determine whether a view is in the view hierarchy of a parent view. Because the root view in a view hierarchy has no parent, its superview property is set to nil. For views currently onscreen, the window object is typically the root view of the hierarchy.

You can use the window property of a view to get a pointer to the window that currently contains the view (if any). This property is set to nil if the view is not currently attached to a window.

Converting Coordinates in the View Hierarchy

At various times, particularly when handling events, an application may need to convert coordinate values from one frame of reference to another. For example, touch events usually report the touch location using the coordinate system of the window, but view objects need that information in the local coordinate system of the view, which may be different. The UIView class defines the following methods for converting coordinates to and from the view’s local coordinate system:

The convert...:fromView: methods convert coordinates to the view’s local coordinate system, while the convert...:toView: methods convert coordinates from the view’s local coordinate system to the coordinate system of the specified view. If you specify nil as the reference view for any of the methods, the conversions are made to and from the coordinate system of the window that contains the view.

In addition to the UIView conversion methods, the UIWindow class also defines several conversion methods. These methods are similar to the UIView versions except that instead of converting to and from a view’s local coordinate system, these methods convert to and from the window’s coordinate system.

Coordinate conversions are straightforward when neither view is rotated or when dealing only with points. When converting rectangles or sizes between views with different rotations, the geometric structure must be altered in a reasonable way so that the resulting coordinates are correct. When converting a rectangle, the UIView class assumes that you want to guarantee coverage of the original screen area. To this end, the converted rectangle is enlarged so that when located in the appropriate view, it completely covers the original rectangle. Figure shows the conversion of a rectangle in the rotatedView object's coordinate system to that of its superview, outerView.

Converting values in a rotated view

Converting values in a rotated view

When converting size information, UIView simply treats it as a delta offset from (0.0, 0.0) that you need to convert from one view to another. Though the offset distance remains the same, the balance along the two axes shifts according to the rotation. When converting sizes, UIKit always returns sizes that consist of positive numbers.

Tagging Views

The UIView class contains a tag property that you can use to tag individual view objects with an integer value. You can use tags to uniquely identify views inside your view hierarchy and to perform searches for those views at runtime. (Tag-based searches are faster than iterating the view hierarchy yourself.) The default value for the tag property is 0.

To search for a tagged view, use the viewWithTag: method of UIView. This method searches the receiver’s subviews using a depth-first search, starting with the receiver itself.

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd Protection Status