View Programming Guide for iOS

View and Window Architecture

View Architecture Fundamentals

Changing the size of a parent view has a ripple effect that can cause the size and position of any subviews to change too. When you change the size of a parent view, you can control the resizing behavior of each subview by configuring the view appropriately. Other changes that affect subviews include hiding a superview, changing a superview’s alpha (transparency), or applying a mathematical transform to a superview’s coordinate system.
改变父视图的size会影响子view的尺寸和位置

The View Drawing Cycle

  • setNeedsDisplay
  • setNeedsDisplayInRect:

Content Modes

每个view都有Content Mode ,决定当view在改变时如何循环使用它的内容来回应改变,。

When a view is first displayed, it renders its content as usual and the results are captured in an underlying bitmap. After that, changes to the view’s geometry do not always cause the bitmap to be recreated. Instead, the value in the contentMode property determines whether the bitmap should be scaled to fit the new bounds or simply pinned to one corner or edge of the view.

The content mode of a view is applied whenever you do the following:

  • Change the width or height of the view’s frame or bounds rectangles.
  • Assign a transform that includes a scaling factor to the view’s transform property.

Stretchable Views

Built-In Animation Support

Among the properties you can animate on a UIView object are the following:

  • frame—Use this to animate position and size changes for the view.
  • bounds—Use this to animate changes to the size of the view.
  • center—Use this to animate the position of the view.
  • transform—Use this to rotate or scale the view.
  • alpha—Use this to change the transparency of the view.
  • backgroundColor—Use this to change the background color of the view.
  • contentStretch—Use this to change how the view’s contents stretch.

View Geometry and Coordinate Systems

The Relationship of the Frame, Bounds, and Center Properties

  • The frame property contains the frame rectangle, which specifies the size and location of the view in its superview’s coordinate system.
  • The bounds property contains the bounds rectangle, which specifies the size of the view (and its content origin) in the view’s own local coordinate system.
  • The center property contains the known center point of the view in the superview’s coordinate system.

You use the center and frame properties primarily for manipulating the geometry of the current view. For example, you use these properties when building your view hierarchy or changing the position or size of a view at runtime. If you are changing only the position of the view (and not its size), the center property is the preferred way to do so. The value in the center property is always valid, even if scaling or rotation factors have been added to the view’s transform. The same is not true for the value in the frame property, which is considered invalid if the view’s transform is not equal to the identity transform.

Coordinate System Transformations

Note: When modifying the transform property of your view, all transformations are performed relative to the center point of the view.

current transformation matrix (CTM)

The coordinate system of each subview builds upon the coordinate systems of its ancestors. So when you modify a view’s transform property, that change affects the view and all of its subviews. However, these changes affect only the final rendering of the views on the screen. Because each view draws its content and lays out its subviews relative to its own bounds, it can ignore its superview’s transform during drawing and layout.

Important: If a view’s transform property is not the identity transform, the value of that view’s frame property is undefined and must be ignored. When applying transforms to a view, you must use the view’s bounds and center properties to get the size and position of the view. The frame rectangles of any subviews are still valid because they are relative to the view’s bounds.
一个view的transform属性不是identity的话,此时的view的frame的行为是无定义的,因此要忽略,只能用center或者bounds

Points Versus Pixels

The Runtime Interaction Model for Views

drawing_model.jpg
  1. The user touches the screen.
  • The hardware reports the touch event to the UIKit framework.
  • The UIKit framework packages the touch into a UIEvent object and dispatches it to the appropriate view. (For a detailed explanation of how UIKit delivers events to your views, see Event Handling Guide for iOS.)
  • The event-handling code of your view responds to the event. For example, your code might:
  • Change the properties (frame, bounds, alpha, and so on) of the view or its subviews.
  • Call the setNeedsLayout method to mark the view (or its subviews) as needing a layout update.
  • Call the setNeedsDisplay or setNeedsDisplayInRect: method to mark the view (or its subviews) as needing to be redrawn.
  • Notify a controller about changes to some piece of data.
    Of course, it is up to you to decide which of these things the view should do and which methods it should call.
  • If the geometry of a view changed for any reason, UIKit updates its subviews according to the following rules:
    a. If you have configured autoresizing rules for your views, UIKit adjusts each view according to those rules. For more information about how autoresizing rules work, see Handling Layout Changes Automatically Using Autoresizing Rules.
    b. If the view implements the layoutSubviews method, UIKit calls it.
    You can override this method in your custom views and use it to adjust the position and size of any subviews. For example, a view that provides a large scrollable area would need to use several subviews as “tiles” rather than create one large view, which is not likely to fit in memory anyway. In its implementation of this method, the view would hide any subviews that are now offscreen or reposition them and use them to draw newly exposed content. As part of this process, the view’s layout code can also invalidate any views that need to be redrawn.
  • If any part of any view was marked as needing to be redrawn, UIKit asks the view to redraw itself.
    For custom views that explicitly define a drawRect: method, UIKit calls that method. Your implementation of this method should redraw the specified area of the view as quickly as possible and nothing else. Do not make additional layout changes at this point and do not make other changes to your application’s data model. The purpose of this method is to update the visual content of your view.
    Standard system views typically do not implement a drawRect: method but instead manage their drawing at this time.
  • Any updated views are composited with the rest of the application’s visible content and sent to the graphics hardware for display.
  • The graphics hardware transfers the rendered content to the screen.

Setting the Properties of a View

  • autoresizingMask, autoresizesSubviews

These properties affect the automatic resizing behavior of the view and its subviews. The autoresizingMask property controls how a view responds to changes in its parent view’s bounds. The autoresizesSubviews property controls whether the current view’s subviews are resized at all.

Tagging Views for Future Identification

viewWithTag:从当前view开始深度优先搜索,直到找到tag对应view,不对父view搜索,tag默认值为0

Adding and Removing Subviews

  • addSubview:
  • bringSubviewToFront:, sendSubviewToBack:
  • exchangeSubviewAtIndex:withSubviewAtIndex:
  • removeFromSuperview

子view的frame超出父view的bounds,子view默认是不会被裁剪的,可用clipsToBounds

One place where you might add subviews to a view hierarchy is in the loadView or viewDidLoad methods of a view controller. If you are building your views programmatically, you put your view creation code in the loadView method of your view controller. Whether you create your views programmatically or load them from a nib file, you could include additional view configuration code in the viewDidLoad method.

load view中创建视图层级,viewdidload中添加额外操作

window没有superview,每个view都有window属性,指向他所在的window

Hiding Views

hidden views do participate in autoresizing and other layout operations associated with the view hierarchy.

Important: If you hide a view that is currently the first responder, the view does not automatically resign its first responder status. Events targeted at the first responder are still delivered to the hidden view. To prevent this from happening, you should force your view to resign the first responder status when you hide it. For more information about the responder chain,

Locating Views in a View Hierarchy

There are two ways to locate views in a view hierarchy:

  • Store pointers to any relevant views in an appropriate location, such as in the view controller that owns the views.
  • Assign a unique integer to each view’s tag property and use the viewWithTag: method to locate it.

Translating, Scaling, and Rotating Views

CGAffineTransform

In addition, any transformations you add are applied to the view relative to its center point.

Converting Coordinates in the View Hierarchy

  • convertPoint:fromView:
  • convertRect:fromView:
  • convertPoint:toView:
  • convertRect:toView:

当转换一个已经旋转的view的时候,如下图,转换出来的是能包住这个旋转图形的最小矩形

uiview_convert_rotated.jpg

Adjusting the Size and Position of Views at Runtime

Whenever the size of a view changes, the size and position of its subviews must change accordingly. The UIView class supports both the automatic and manual layout of views in a view hierarchy. With automatic layout, you set the rules that each view should follow when its parent view resizes, and then forget about resizing operations altogether. With manual layout, you manually adjust the size and position of views as needed.

Being Prepared for Layout Changes

Layout changes can occur whenever any of the following events happens in a view:

  • view的bounds发生改变
  • 用户界面方向发生改变,通常会改变bounds
  • The set of Core Animation sublayers associated with the view’s layer changes and requires layout
  • Your application forces layout to occur by calling the setNeedsLayout or layoutIfNeeded method of a view
  • Your application forces layout by calling the setNeedsLayout method of the view’s underlying layer object.

Handling Layout Changes Automatically >Using Autoresizing Rules

When you change the size of a view, the position and size of any embedded subviews usually needs to change to account for the new size of their parent. The autoresizesSubviews property of the superview determines whether the subviews resize at all. If this property is set to YES, the view uses the autoresizingMask property of each subview to determine how to size and position that subview. Size changes to any subviews trigger similar layout adjustments for their embedded subviews.

  • autoresizingMask property

autoresizing的局限在于都是相对于父视图的

Modifying Views at Runtime

Embedding Layer Objects in a View

Checklist for Implementing a Custom View

  • If your view class manages one or more integral subviews, do the following:
  • Create those subviews during your view’s initialization sequence.
  • Set the autoresizingMask property of each subview at creation time.
  • If your subviews require custom layout, override the layoutSubviews method and implement your layout code there.

Initializing Your Custom View

Implementing Your Drawing Code

Before calling your view’s drawRect: method, UIKit configures the basic drawing environment for your view. Specifically, it creates a graphics context and adjusts the coordinate system and clipping region to match the coordinate system and visible bounds of your view. Thus, by the time your drawRect: method is called, you can begin drawing your content using native drawing technologies such as UIKit and Core Graphics. You can get a pointer to the current graphics context using the UIGraphicsGetCurrentContext function.

Important: The current graphics context is valid only for the duration of one call to your view’s drawRect: method. UIKit might create a different graphics context for each subsequent call to this method, so you should not try to cache the object and use it later.
当你确保view不透明时,设置opaque为YES,这样可以减少绘制内容。

Responding to Events

  • 直接使用手势
  • 使用touch
  • touchesBegan:withEvent:
  • touchesMoved:withEvent:
  • touchesEnded:withEvent:
  • touchesCancelled:withEvent:

直接使用touch注意

The default behavior for views is to respond to only one touch at a time. If the user puts a second finger down, the system ignores the touch event and does not report it to your view. If you plan to track multi-finger gestures from your view’s event-handler methods, you need to enable multitouch events by setting the multipleTouchEnabled property of your view to YES.

UIView发生动画时禁止交互

Note: The animation methods of UIView typically disable touch events while animations are in progress. You can override this behavior by configuring the animation appropriately. For more information about performing animations, see Animations.

hitTest:withEvent: 和 pointInside:withEvent:

As it handles touch events, UIKit uses the hitTest:withEvent: and pointInside:withEvent: methods of UIView to determine whether a touch event occurred inside a given view’s bounds. Although you rarely need to override these methods, you could do so to implement custom touch behaviors for your view. For example, you could override these methods to prevent subviews from handling touch events.

Windows

一般应用只有一个window,但也有例外,比如播放视频时会新建一个window,或者电话来时新建一个window

Changing the Window Level

应用一般window的等级为normal。高等级window应用于将内容展示在应用的最上方

For example, when you show or hide the status bar or display an alert view, the system automatically creates the needed windows to display those items.

Displaying Content on an External Display

推荐阅读更多精彩内容