View and Window Architecture
视图和窗口架构
Views and windows present your application’s user interface and handle the interactions with that interface. UIKit and other system frameworks provide a number of views that you can use as-is with little or no modification. You can also define custom views for places where you need to present content differently than the standard views allow.
视图和窗口表现了应用程序的用户界面,并处理与该界面的各种交互。 UIKit 和其它系统框架提供了很多你可以不修改或做很少修改就能直接使用的各种视图。如果标准视图所表示的内容不符合你的需求,你也可以自定义视图。
Whether you use the system views or create your own custom views, you need to understand the infrastructure provided by the UIView
and UIWindow
classes. These classes provide sophisticated facilities for managing the layout and presentation of views. Understanding how those facilities work is important for making sure your views behave appropriately when changes occur in your application.
无论你是使用系统视图还是自己创建自定义视图,你都需要理解UIView 类 和UIWindow类提供的基础设施。
View Architecture Fundamentals
视图架构基础
Most of the things you might want to do visually are done with view objects—instances of the UIView
class. A view object defines a rectangular region on the screen and handles the drawing and touch events in that region. A view can also act as a parent for other views and coordinate the placement and sizing of those views. The UIView
class does most of the work in managing these relationships between views, but you can also customize the default behavior as needed.
大多数你可能想要可视化的事情都是由视图对象完成的---这些视图对象都是UIView 类的实例。视图对象在屏幕上定义了一个矩形区域,并在该区域内处理绘制和触摸事件。 视图也可以作为其它视图的父视图,并为那些视图定位和定尺寸。 UIView类负责管理这些视图间关系的大多数工作, 但是如果需要,你也可以定制默认行为。
Views work in conjunction with Core Animation layers to handle the rendering and animating of a view’s content. Every view in UIKit is backed by a layer object (usually an instance of the CALayer
class), which manages the backing store for the view and handles view-related animations. Most operations you perform should be through the UIView
interface. However, in situations where you need more control over the rendering or animation behavior of your view, you can perform operations through its layer instead.
视图跟内核动画(Core Animation)层连接来处理渲染(模型到图像)或动画视图的内容。 UIKit框架里的每个视图的背后都是一个层对象(通常是CALayer类的一个实例),层对象管理视图的后台存储,并处理视图相关的各种动画。 你执行的大多数操作都经过UIView接口。 然而,在你需要更多的控制,不止渲染或动画视图的行为时,你可以通过它的层代替视图执行操作。
To understand the relationship between views and layers, it helps to look at an example. Figure 1-1 shows the view architecture from the ViewTransitions sample application along with the relationship to the underlying Core Animation layers. The views in the application include a window (which is also a view), a generic UIView
object that acts as a container view, an image view, a toolbar for displaying controls, and a bar button item (which is not a view itself but which manages a view internally). (The actual ViewTransitions sample application includes an additional image view that is used to implement transitions. For simplicity, and because that view is usually hidden, it is not included in Figure 1-1.) Every view has a corresponding layer object that can be accessed from that view’s layer
property. (Because a bar button item is not a view, you cannot access its layer directly.) Behind those layer objects are Core Animation rendering objects and ultimately the hardware buffers used to manage the actual bits on the screen.
为了理解视图和层之间的关系,看例子比较直观。 图1-1 显示了ViewTransitions 例程应用中的视图结构,以及跟下面的内核动画层之间的关系。应用程序中的视图包含一个窗口(也是一个视图), 一个通用UIView对象,它作为一个容器视图(container view), 一个图片视图, 一个工具栏,用来显示控制键, 以及一个工具栏上的按钮项(本身不是一个视图,但是在内部管理了一个视图)。(真正的ViewTransitions 例程应用还包含一个额外的图片视图,用来实现变换。 为了方便,因为那个视图通常是被隐藏的,所以没在图1-1里包含) 每个视图都对应着一个层对象,该层对象能从视图的layer 属性被访问。(因为栏按钮项不是一个视图,你不能直接访问它的层) 那些层对象后面是内核动画渲染对象,最后硬件缓冲(hardware buffers)管理屏幕上的实际位(bits)。
Architecture of the views in a sample application
The use of Core Animation layer objects has important implications for performance. The actual drawing code of a view object is called as little as possible, and when the code is called, the results are cached by Core Animation and reused as much as possible later. Reusing already-rendered content eliminates the expensive drawing cycle usually needed to update views. Reuse of this content is especially important during animations, where the existing content can be manipulated. Such reuse is much less expensive than creating new content.
内核动画层对象的使用对性能(performance)有很重要的意义。 视图的对象的真实绘图代码会被尽可能少的调用,当代码被调用了之后,结果被缓存在内核动画,并在以后尽可能多的重复使用。 重用已经被渲染的内容消除了视图更新所需要的昂贵绘图周期。动画时重用这些已经存在的内容尤其重要。 这样的重用比创建新内容节省消耗。
View Hierarchies and Subview Management
视图层次以及子视图管理
In addition to providing its own content, a view can act as a container for other views. When one view contains another, a parent-child relationship is created between the two views. The child view in the relationship is known as the subview and the parent view is known as the superview. The creation of this type of relationship has implications for both the visual appearance of your application and the application’s behavior.
除了提供它自己的内容,视图还能作为其它视图的容器。当一个视图容纳了另一个视图,那么这2个视图之间就建立了父子关系。 关系中的子视图通常被称为子视图(subview),而父视图则被称为superview。这种关系的建立对应用程序的可见外观以及它的行为都很有意义。
Visually, the content of a subview obscures all or part of the content of its parent view. If the subview is totally opaque, then the area occupied by the subview completely obscures the corresponding area of the parent. If the subview is partially transparent, the content from the two views is blended together prior to being displayed on the screen. Each superview stores its subviews in an ordered array and the order in that array also affects the visibility of each subview. If two sibling subviews overlap each other, the one that was added last (or was moved to the end of the subview array) appears on top of the other.
外表上,子视图的内容包含了父视图内容的全部或一部分。 如果子视图是完全不透明的,则它完全占据了父视图的相应区域。 如果子视图部分透明,则两个视图的内容在屏幕上会被重叠显示。每个父视图把它们的子视图按照一定顺序存在一个数组里,该顺序也影响了每个子视图的可见性。 如果2个兄弟子视图重叠在一起,则后加(或被移到子视图数组的末尾的)的视图在前一个视图的上面。
The superview-subview relationship also impacts several view behaviors. 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.
父子视图关系还影响了一些视图行为。 改变父视图的大小,同时也将让子视图的尺寸和位置发生改变。 当你改变父视图的尺寸时,你可以通过适当的配置视图来控制每个子视图的大小调整行为(resizing behavior)。 其它影响子视图的变化还有隐藏父视图,改变父视图的透明度,或给父视图的定位系统应用一个数学变换。
The arrangement of views in a view hierarchy also determines how your application responds to events. When a touch occurs inside a specific view, the system sends an event object with the touch information directly to that view for handling. However, if the view does not handle a particular touch event, it can pass the event object along to its superview. If the superview does not handle the event, it passes the event object to its superview, and so on up the responder chain. Specific views can also pass the event object to an intervening responder object, such as a view controller. If no object handles the event, it eventually reaches the application object, which generally discards it.
视图在视图层次里的排列顺序还决定了应用程序如何对事件做出反应。当在一个指定视图里发生一个触摸事件,系统直接给那个视图发送了一个事件对象以及触摸信息让其处理。 然而,如果该视图没有处理一个特殊的触摸事件,它可以把事件传递给它的父视图。 如果它的父视图还没有处理该事件,则把事件传递给父视图的父视图,以此类推。指定视图还可以传递事件给一个介于中间的响应对象,比如一个视图控制器。如果没有对象能处理该事件,它最终会被传递到应用程序对象,通常由应用程序对象把它丢弃。
For more information about how to create view hierarchies, see “Creating and Managing a View Hierarchy.”
关于如何创建视图层次的更多信息,请看“Creating and Managing a View Hierarchy.”
The View Drawing Cycle
视图绘制周期
The UIView
class uses an on-demand drawing model for presenting content. When a view first appears on the screen, the system asks it to draw its content. The system captures a snapshot of this content and uses that snapshot as the view’s visual representation. If you never change the view’s content, the view’s drawing code may never be called again. The snapshot image is reused for most operations involving the view. If you do change the content, you notify the system that the view has changed. The view then repeats the process of drawing the view and capturing a snapshot of the new results.
UIView 类使用一个按需绘制模型(on-demand drawing model)来呈现视图内容。 当视图第一次出现在屏幕上时,系统要求它绘制其内容。 系统捕捉该内容的快照,并使用该快照作为视图的视觉代理(visual representation)。 如果你从来没有改变视图的内容,那视图的绘制代码可能永远也不会再被调用。快照图片被视图设计的大多数操作所重用。如果你对内容做了改变,你需要通知系统告诉它视图已经改变。 然后视图重复绘制视图过程,重新捕捉新的快照。
When the contents of your view change, you do not redraw those changes directly. Instead, you invalidate the view using either the setNeedsDisplay
or setNeedsDisplayInRect:
method. These methods tell the system that the contents of the view changed and need to be redrawn at the next opportunity. The system waits until the end of the current run loop before initiating any drawing operations. This delay gives you a chance to invalidate multiple views, add or remove views from your hierarchy, hide views, resize views, and reposition views all at once. All of the changes you make are then reflected at the same time.
当视图内容发生改变时,你不会直接重新绘制那些改变。你可以用 setNeedsDisplay
或 setNeedsDisplayInRect: 方法让视图无效。 这些方法告诉系统视图的内容已经发生改变,需要在下次重新绘制。 系统在直到当前运行循环(current run loop)结束,在任何绘制操作初始化之前一直等待。 该等待给你一次机会,用来无效多个视图,添加或从视图层次里删除视图,隐藏视图,调整视图大小,一次性重新定位所有视图等。所有这些你做的变化将在同一时间反映。
Note: Changing a view’s geometry does not automatically cause the system to redraw the view’s content. The view’scontentMode
property determines how changes to the view’s geometry are interpreted. Most content modes stretch or reposition the existing snapshot within the view’s boundaries and do not create a new one. For more information about how content modes affect the drawing cycle of your view, see “Content Modes.”
注意:改变视图的几个外形并不会自动导致系统重画视图内容。 视图的contentMode 属性解释了如何对视图几何外形做改变。大多数内容模式都是在视图边界里拉伸或重定位已经存在的快照,并不需要创建新视图内容。了解更多关于内容模式如何影响视图的绘制周期,请看 “Content Modes.”
When the time comes to render your view’s content, the actual drawing process varies depending on the view and its configuration. System views typically implement private drawing methods to render their content. Those same system views often expose interfaces that you can use to configure the view’s actual appearance. For custom UIView
subclasses, you typically override the drawRect:
method of your view and use that method to draw your view’s content. There are also other ways to provide a view’s content, such as setting the contents of the underlying layer directly, but overriding thedrawRect:
method is the most common technique.
当开始渲染视图内容时,实际绘图进程变化取决于视图和它的配置。 系统视图通常实现似有绘图方法来渲染它们的内容。 那些相同的系统视图常常暴露出你可以用来配置视图真实外观的接口。比如定制UIView 子类,你通常重载视图的drawRect: 方法,并用该方法绘制视图的内容。还有其它方法来提供一个视图的内容,比如直接设置下面的层内容,但是重载 drawRect: 方法是最通用的技术。
For more information about how to draw content for custom views, see “Implementing Your Drawing Code.”
更多有关如果绘制自定义视图的内容方面的信息,请看 “Implementing Your Drawing Code.”
Content Modes(内容模式)
Each view has a content mode that controls how the view recycles its content in response to changes in the view’s geometry and whether it recycles its content at all. 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.
每个视图都有一个内容模式,在视图几何外形发生变化时,用来控制视图如何回收它的内容来响应视图几何外形的改变,以及是否回收其全部内容。 当视图被第一次显示时,它跟平时一样渲染它的内容,结果被捕捉到一个基本的位图里。接着,视图几何外形的改变并不总是导致重新创建位图。相反,contentMode 属性的值决定了该位图是否应该缩放来适应新的要求,或只需要简单的固定到视图的一个角落或一边。
The content mode of a view is applied whenever you do the following:
视图的内容模式被应用到以下情况:
-
Change the width or height of the view’s
frame
orbounds
rectangles. -
Assign a transform that includes a scaling factor to the view’s
transform
property.给视图transform的属性分配一个变换,该变换包含一个缩放因子。
By default, the contentMode
property for most views is set to UIViewContentModeScaleToFill
, which causes the view’s contents to be scaled to fit the new frame size. Figure 1-2 shows the results that occur for some content modes that are available. As you can see from the figure, not all content modes result in the view’s bounds being filled entirely, and those that do might distort the view’s content.
默认时, 大多数视图的内容模式(contentMode)属性被设为UIViewContentModeScaleToFill,该设置导致视图的内容被缩放以适应新的框架尺寸。 图1-2显示了一些可用的内容模式效果。正如你在图中看到,不是所有的内容模式导致视图边界被完全填满, 那些确实填满边界的图形可能失真(distort)。
图 1-2 内容模式比较
Content modes are good for recycling the contents of your view, but you can also set the content mode to theUIViewContentModeRedraw
value when you specifically want your custom views to redraw themselves during scaling and resizing operations. Setting your view’s content mode to this value forces the system to call your view’s drawRect:
method in response to geometry changes. In general, you should avoid using this value whenever possible, and you should certainly not use it with the standard system views.
内容模式对于回收视图内容很好,但是你也可以设置内容模式为 UIViewContentModeRedraw 值,如果你特别想要你的自定义视图在缩放和大小调整操作时也重新绘制时。把你的视图内容模式设置为该值强制系统在视图几何外形发生变化时调用 drawRect: 方法。 一般来说,你应该尽可能的避免使用该值,而且确定不把它跟标准系统视图一起使用。
For more information about the available content modes, see UIView Class Reference.
更多有关可用内容模式的信息,请看 UIView Class Reference.
Stretchable Views
可拉伸视图
You can designate a portion of a view as stretchable so that when the size of the view changes only the content in the stretchable portion is affected. You typically use stretchable areas for buttons or other views where part of the view defines a repeatable pattern. The stretchable area you specify can allow for stretching along one or both axes of the view. Of course, when stretching a view along two axes, the edges of the view must also define a repeatable pattern to avoid any distortion.Figure 1-3 shows how this distortion manifests itself in a view. The color from each of the view’s original pixels is replicated to fill the corresponding area in the larger view.
你可以设计视图的一部分为可拉伸的,这样当视图的大小发生改变时,只有可拉伸部分的内容受到影响。 通常在按钮或有部分视图定义了一个可重复图案的其它视图里使用可拉伸区域。你指定的可拉伸区域可以允许在一个或两个轴方向上拉伸视图。 当然,当视图沿着2个轴被拉伸时,视图边缘必须也定义一个可重复的图案,用来避免任何失真。 图1-3 显示了失真的情况。 视图的每个初始像素颜色被复制到了一个更大视图的相应区域里。
Stretching the background of a button
图 1-3 拉伸按钮的背景
You specify the stretchable area of a view using the contentStretch
property. This property accepts a rectangle whose values are normalized to the range 0.0
to 1.0
. When stretching the view, the system multiplies these normalized values by the view’s current bounds and scale factor to determine which pixel or pixels need to be stretched. The use of normalized values alleviates the need for you to update the contentStretch
property every time the bounds of your view change.
你可以用contentStretch 属性指定视图的可拉伸区域。 该属性接受一个0.0 到1.0之间的正常值。当拉伸视图时,系统用这些正常值乘以视图的当前范围和缩放因子来决定哪个像素或哪些像素需要被拉伸。 标准化值的使用缓解了每次视图边界变化时必须更新contentStretch属性的需求。
The view’s content mode also plays a role in determining how the view’s stretchable area is used. Stretchable areas are only used when the content mode would cause the view’s content to be scaled. This means that stretchable views are supported only with the UIViewContentModeScaleToFill
, UIViewContentModeScaleAspectFit
, andUIViewContentModeScaleAspectFill
content modes. If you specify a content mode that pins the content to an edge or corner (and thus does not actually scale the content), the view ignores the stretchable area.
视图内容模式还决定了如何使用视图的可拉伸区域。 可拉伸区域只在内容模式将导致视图的内容被缩放时使用。 这意味着可拉伸视图只支持 UIViewContentModeScaleToFill
, UIViewContentModeScaleAspectFit
, 和 UIViewContentModeScaleAspectFill 内容模式。如果你指定了一个把内容固定到一边或一角的内容模式(就是不会拉伸内容),视图将忽视可拉伸区域。
Note: The use of the contentStretch
property is recommended over the creation of a stretchable UIImage
object when specifying the background for a view. Stretchable views are handled entirely in the Core Animation layer, which typically offers better performance.
注意:contentStretch 属性在创建一个可拉伸 UIImage 对象,指定视图的背景时推荐使用。可拉伸视图全部在内核动画层里处理,内核动画层通常提供了更好的性能。
Built-In Animation Support
内置动画支持
One of the benefits of having a layer object behind every view is that you can animate many view-related changes easily. Animations are a useful way to communicate information to the user and should always be considered during the design of your application. Many properties of the UIView
class are animatable—that is, semiautomatic support exists for animating from one value to another. To perform an animation for one of these animatable properties, all you have to do is:
每个视图后面都有一个层对象的好处之一是你可以简单的让几个视图相关的变化通过动画完成。 动画是将信息传递给用户的一种很有用的方式,在应用程序设计过程中应该始终被考虑。UIView 类的很多属性都是可动画的---就是,半自动化支持动画从一个值到另一个值。 为了让这些属性执行一个动画,你只需要做:
-
Tell UIKit that you want to perform an animation.
告诉UIKit 你想要执行一个动画。
-
Change the value of the property.
改变属性的值。
Among the properties you can animate on a UIView
object are the following:
支持动画的UIView 对象属性包括:
-
frame
—Use this to animate position and size changes for the view.frame
—用它让视图的位置和尺寸变换发生动画 -
bounds
—Use this to animate changes to the size of the view.bounds
—用它让视图的尺寸变化发生动画 -
center
—Use this to animate the position of the view.center
— 用它定位视图 -
transform
—Use this to rotate or scale the view.transform
— 用它旋转或缩放视图 -
alpha
—Use this to change the transparency of the view.alpha
— 用它改变视图的透明度 -
backgroundColor
—Use this to change the background color of the view.backgroundColor
— 用它改变视图的背景颜色 -
contentStretch
—Use this to change how the view’s contents stretch.contentStretch— 用它改变视图如何拉伸
One place where animations are very important is when transitioning from one set of views to another. Typically, you use a view controller to manage the animations associated with major changes between parts of your user interface. For example, for interfaces that involve navigating from higher-level to lower-level information, you typically use a navigation controller to manage the transitions between the views displaying each successive level of data. However, you can also create transitions between two sets of views using animations instead of a view controller. You might do so in places where the standard view-controller animations do not yield the results you want.
一个动画应用很重要的地方是从一个视图集过渡到另一个视图集。通常,你使用一个视图控制器来管理跟用户界面各部分之间的主要变换有关的动画。比如,涉及从高级别信息导航到低级别信息的界面时,你通常会使用一个导航控制器来管理显示每个连续级别数据的视图之间的过渡。然而,你也可以用动画来创建2个视图集之间的过渡,而不用视图控制器。 当标准试图控制动画不能得到你想要的效果时,你可能会这样做。
In addition to the animations you create using UIKit classes, you can also create animations using Core Animation layers. Dropping down to the layer level gives you much more control over the timing and properties of your animations.
除了用UIKit类来创建动画,你还可以用内核动画层来创建动画。 下降到层级别让你控制更多的动画时机和属性。
For details about how to perform view-based animations, see “Animations.” For more information about creating animations using Core Animation, see Core Animation Programming Guide and Core Animation Cookbook.
有关如何执行基于视图的动画的更多详情,请看“Animations.” 更多关于用内核动画创建动画的信息,请看Core Animation Programming Guide 和 Core Animation Cookbook.
View Geometry and Coordinate Systems
视图的几何和坐标系统
The default coordinate system in UIKit has its origin in the top-left corner and has axes that extend down and to the right from the origin point. Coordinate values are represented using floating-point numbers, which allow for precise layout and positioning of content regardless of the underlying screen resolution. Figure 1-4 shows this coordinate system relative to the screen. In addition to the screen coordinate system, windows and views define their own local coordinate systems that allow you to specify coordinates relative to the view or window origin instead of relative to the screen.
UIKit 框架的默认坐标系统的原点是在左上角, 并有从原点开始向下和向右的坐标轴。坐标值由浮点-点数字表示,它被用于精确的布局和内容的定位,不需管底层的屏幕分辨率。 图1-4 显示了相对于屏幕的该坐标系统。 除了屏幕坐标系统,窗口和视图还定义了它们自己的本地坐标系统,用来让你指定坐标,该坐标相对于视图或窗口原点的,而不是相对于屏幕的坐标。
Coordinate system orientation in UIKit
图1-4 UIKit 框架的坐标系统。
Because every view and window defines its own local coordinate system, you need to be aware of which coordinate system is in effect at any given time. Every time you draw into a view or change its geometry, you do so relative to some coordinate system. In the case of drawing, you specify coordinates relative to the view’s own coordinate system. In the case of geometry changes, you specify coordinates relative to the superview’s coordinate system. The UIWindow
and UIView
classes both include methods to help you convert from one coordinate system to another.
因为每个视图和窗口都定义了自己的本地坐标系统,你需要在任何时候都意识到是哪个坐标系统在起作用。每次当你绘制一个视图或改变它的几何外形时,你都将根据一些坐标系统来做定位。 在绘图时,你指定跟视图本身的坐标系统相关的坐标。 在几何外形发生变化时,你指定跟父视图的坐标系统有关的坐标。UIWindow 和 UIView 类都包含了各种帮助你转换坐标系统的方法。
Important: Some iOS technologies define default coordinate systems whose origin point and orientation differ from those used by UIKit. For example, Core Graphics and OpenGL ES use a coordinate system whose origin lies in the lower-left corner of the view or window and whose y-axis points upward relative to the screen. Your code must take such differences into account when drawing or creating content and adjust coordinate values (or the default orientation of the coordinate system) as needed.
重要: 一些iOS 技术定义了默认坐标系统,它们的原点和坐标轴方向都跟UIKit框架不同。 比如, Core Graphics 和 OpenGL ES 的坐标系统原点位于视图或窗口的左下角,y轴向上延伸。 你的代码在绘图或创建内容时必须计算到这些区别,并根据需要调整坐标值(或坐标系统的默认方向)。
The Relationship of the Frame, Bounds, and Center Properties
Frame, Bounds, Center属性之间的关系
A view object tracks its size and location using its frame
, bounds
, and center
properties:
视图对象用frame, bounds, 和 center 属性监测它的尺寸和位置。
-
The
frame
property contains the frame rectangle, which specifies the size and location of the view in its superview’s coordinate system.frame 属性包含了框架矩形, 它指定了视图的尺寸和以及它在父视图坐标系统中的位置。
-
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.bounds 属性包含了边界矩形, 它指定了视图在它自己的坐标系统中的的尺寸(以及它的初始内容)。
-
The
center
property contains the known center point of the view in the superview’s coordinate system.center 属性 包含了已知的视图中心点,该中心点以父视图坐标系统为参考。
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 thecenter
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.
你主要使用center 和 frame 属性来操纵当前视图的几何外形。 比如, 当你建立视图层次或在运行时改变视图的位置或尺寸时使用它们。 如果你只改变视图的位置,而不改变它的大小,则center属性是最好的选择。 center 属性里的值永远都是有效的,即使缩放或旋转因子已经被添加到视图的变换(transform)里。 同样的情况下,frame属性里的值则不正确,因为该值在视图的变换不是恒等变换时,被认为无效。
You use the bounds
property primarily during drawing. The bounds rectangle is expressed in the view’s own local coordinate system. The default origin of this rectangle is (0, 0) and its size matches the size of the frame rectangle. Anything you draw inside this rectangle is part of the view’s visible content. If you change the origin of the bounds rectangle, anything you draw inside the new rectangle becomes part of the view’s visible content.
在绘图时,bounds 属性是主要被使用的属性。 边界矩形表示在视图自己的本地坐标系统里。 该矩形的默认原点为(0,0),并且它的大小跟框架矩形的大小一致。 任何在该矩形里绘制的东西都是视图可见内容的一部分。 如果你改变了边界矩形的原点,任何你在新矩形里绘制的内容就成为视图可见内容的一部分。
Figure 1-5 shows the relationship between the frame and bounds rectangles for an image view. In the figure, the upper-left corner of the image view is located at the point (40, 40) in its superview’s coordinate system and the size of the rectangle is 240 by 380 points. For the bounds rectangle, the origin point is (0, 0) and the size of the rectangle is similarly 240 by 380 points.
图1-5显示了一个图像视图(image view)的框架矩形(frame rectangle)和边界矩形(bounds rectangle)之间的关系。在图中,图片视图的左上角坐标在它的父视图坐标系里是点(40,40), 图片的尺寸是240x380点。 对于边界矩形来说,原点是(0,0), 矩形大小也是240x380点。
Relationship between a view's frame and bounds
图 1-5 视图框架和边框之间的关系
Although you can change the frame
, bounds
, and center
properties independent of the others, changes to one property affect the others in the following ways:
尽管你可以独立的改变frame, bounds, 和center属性, 但是如果你改变了其中一个属性将对其它属性造成以下方面的影响:
-
When you set the
frame
property, the size value in thebounds
property changes to match the new size of the frame rectangle. The value in thecenter
property similarly changes to match the new center point of the frame rectangle.当你设置frame属性时,bounds属性里的尺寸值将发生变化以匹配框架矩形的新尺寸。 center 属性的值同样被改变以匹配框架矩形的新中心点。
-
When you set the
center
property, the origin value in theframe
changes accordingly.当你设置center属性时, frame里的初始值也相应的发生改变。
-
When you set the size of the
bounds
property, the size value in theframe
property changes to match the new size of the bounds rectangle.当你设置bounds 属性尺寸时, frame 属性里的尺寸也发生改变以匹配边界矩形的新尺寸。
By default, a view’s frame is not clipped to its superview’s frame. Thus, any subviews that lie outside of their superview’s frame are rendered in their entirety. You can change this behavior, though, by setting the superview’s clipsToBounds
property to YES
. Regardless of whether or not subviews are clipped visually, touch events always respect the bounds rectangle of the target view’s superview. In other words, touch events occurring in a part of a view that lies outside of its superview’s bounds rectangle are not delivered to that view.
默认情况下, 视图的框架不会被剪切到它的父视图框架内。 因此, 任何超出它们父视图框架的子视图将全部显示。 但是,你可以通过把父视图的 clipsToBounds 属性设置为YES来改变该行为。不管视觉上子视图是否被裁减, 视图永远只响应它的父视图范围内的触摸事件。换句话说,在父视图边界矩形外发生的触摸事件是不会被传递到该视图的。
Coordinate System Transformations
坐标系转换
Coordinate system transformations offer a way to alter your view (or its contents) quickly and easily. An affine transform is a mathematical matrix that specifies how points in one coordinate system map to points in a different coordinate system. You can apply affine transforms to your entire view to change the size, location, or orientation of the view relative to its superview. You can also use affine transforms in your drawing code to perform the same types of manipulations to individual pieces of rendered content. How you apply the affine transform therefore depends on context:
坐标系转换让你快速简单的变换视图(或内容)。 反射变换(affine transform)是一种数学矩阵,它指定一个坐标系里的点如何对应于一个不同坐标系里的点。 你可以在整个视图里应用反射变换(affine transforms)来改变尺寸,位置或视图的方向,该方向相对于它父视图的方向。 你还可以在你的绘图代码里应用反射变换来对渲染内容的各个独立块做同样类型的操作。因此,根据上下文(context)来决定如何应用反射变换。
-
To modify your entire view, modify the affine transform in the
transform
property of your view.要想修改整个视图,修改视图的
transform 属性中的反射变换。
-
To modify specific pieces of content in your view’s
drawRect:
method, modify the affine transform associated with the active graphics context.要想修改视图drawRect: 方法中特定内容块, 修改跟活动图形上下文(active graphics context)相关联的反射变换。
You typically modify the transform
property of a view when you want to implement animations. For example, you could use this property to create an animation of your view rotating around its center point. You would not use this property to make permanent changes to your view, such as modifying its position or size a view within its superview’s coordinate space. For that type of change, you should modify the frame rectangle of your view instead.
当你想实现动画时,你通常会修改视图的transform属性。 比如,你可以使用该属性来创建一个让视图围绕它的中心点旋转的动画。 你可能不会使用该值来做视图的永久变化,比如修改视图在其父视图的坐标系里的位置或尺寸。 对于那些变化,你应该用修改视图的框架矩形来替代。
Note: When modifying the transform
property of your view, all transformations are performed relative to the center point of the view.
注意:当你修改视图的transform 属性时,所有的变换都是相对于视图的中心点来执行的。
In your view’s drawRect:
method, you use affine transforms to position and orient the items you plan to draw. Rather than fix the position of an object at some location in your view, it is simpler to create each object relative to a fixed point, typically (0, 0), and use a transform to position the object immediately prior to drawing. That way, if the position of the object changes in your view, all you have to do is modify the transform, which is much faster and less expensive than recreating the object at its new location. You can retrieve the affine transform associated with a graphics context using theCGContextGetCTM
function and you can use the related Core Graphics functions to set or modify this transform during drawing.
在视图的drawRect:方法中, 你可以使用反射变换来给你想要绘画的内容做定位和定方向。与其在视图里对一个对象做不同位置的定位,不如根据一个固定点(通常是(0,0))来创建每个对象, 并紧接着在绘图时使用变换(transform)来做对象定位,这样做更加容易。那样,如果视图中的对象位置发生了改变,你只需要修改transform,这样比在新位置重新创建对象更快更省消耗。你可以用 CGContextGetCTM 函数来取回跟一个图形上下文(graphics context)相关联的反射变换, 而且你可以在绘图期间使用相关的内核图形函数来设置或修改该transform.
The current transformation matrix (CTM) is the affine transform in use at any given time. When manipulating the geometry of your entire view, the CTM is the affine transform stored in your view’s transform
property. Inside yourdrawRect:
method, the CTM is the affine transform associated with the active graphics context.
当前变换矩阵(CTM) 是在任何特定时间正在使用的反射变换。 当操纵整个视图的几何外观时, CTM是存储在视图的 transform 属性里的反射变换。在drawRect:方法里, CTM是跟活动图形上下文相关联的反射变换。
The coordinate system of each subview builds upon the coordinate systems of its ancestors. So when you modify a view’stransform
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.
每个子视图的坐标系都建立在它先祖的坐标系基础上。 所以当你修改一个视图的 transform 属性时, 该改变会影响视图及它的所有子视图。 然而,这些改变只影响最终呈现在屏幕上的视图。 因为每个视图绘制它的内容并根据它自己的边界布局它的子视图,所以它在绘图和布局期间能忽略它父视图的变换(transform)。
Figure 1-6 demonstrates how two different rotation factors combine visually when rendered. Inside the view’s drawRect:
method, applying a 45 degree rotation factor to a shape causes that shape to appear rotated by 45 degrees. Applying a separate 45 degree rotation factor to the view then causes the shape to appear to be rotated by 90 degrees. The shape is still rotated by only 45 degrees relative to the view that drew it, but the view rotation makes it appear to be rotated by more.
图1-6 显示了视觉上2个不同旋转因子在渲染时是如何被合并的。在视图的drawRect:方法,给一个图形应用一个旋转45度角的旋转因子,让图形(shape)旋转45度。然后给视图应用一个单独的45度角旋转因子,图形看起来就像被旋转了90度。 而实际上图形相对于绘制它的视图来说任然只旋转了45度, 但是视图的旋转让它看起来旋转了更多。
Rotating a view and its content
图 1-6 旋转视图及它的内容
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.
重要: 如果一个视图的transform属性不是恒等变换,视图的frame属性值就是未定义并必须被忽视。当你给视图应用变换时,你必须使用视图的bounds 和 center属性来获取视图的尺寸和位置。 任何子视图的框架矩形任然有效,因为它们是相对于视图的边界的。
For information about modifying your view’s transform property at runtime, see “Translating, Scaling, and Rotating Views.”For information about how to use transforms to position content during drawing, see Drawing and Printing Guide for iOS.
关于在运行时修改视图变换属性的更多信息,请看“Translating, Scaling, and Rotating Views.” 关于在绘图时如何使用变换来定位内容的信息,请看Drawing and Printing Guide for iOS.
Points Versus Pixels
点与像素
In iOS, all coordinate values and distances are specified using floating-point values in units referred to as points. The measurable size of a point varies from device to device and is largely irrelevant. The main thing to understand about points is that they provide a fixed frame of reference for drawing.
在iOS里,所有坐标值和距离都是用浮点-点单位制值来指定的,简称为点。从设备到设备衡量一个点的变化大小是没有意义的。 理解点的主要原因是它们给绘图提供了一个固定的参考框架。
Table 1-1 lists the screen dimensions (measured in points) for different types of iOS-based devices in a portrait orientation. The width dimension is listed first, followed by the height dimension of the screen. As long as you design your interface to these screen sizes, your views will display correctly on the corresponding type of device.
表 1-1 列出了不同类型设备在垂直方向上的屏幕尺寸(按点衡量),这些尺寸都基于iOS。 屏幕的宽尺寸在前,高尺寸在后。 只要根据这些屏幕尺寸设计,视图将在相关类型的设备上正确显示。
Device |
Screen dimensions (in points) |
---|---|
iPhone and iPod touch |
320 x 480 |
iPad |
768 x 1024 |
The point-based measuring system used for each type of device defines what is known as the user coordinate space. This is the standard coordinate space you use for nearly all of your code. For example, you use points and the user coordinate space when manipulating the geometry of a view or calling Core Graphics functions to draw the contents of your view. Although coordinates in the user coordinate space sometimes map directly to the pixels on the device’s screen, you should never assume that this is the case. Instead, you should always remember the following:
基于点的测量系统应用于每种类型的设备定义,它被称为用户坐标空间。 几乎所有代码都使用该标准坐标空间。 比如, 当你操纵视图的几何外形或调用内核图形函数来绘制视图的内容时, 你将使用点和用户坐标空间。 尽管用户坐标空间里的坐标有时直接跟设备屏幕上的像素相对应, 但你绝不要认为它们就是同一种东西,你应用总是记住以下一点:
-
One point does not necessarily correspond to one pixel on the screen.
一个点并不一定对应于屏幕上的一个像素。
At the device level, all coordinates you specify in your view must be converted to pixels at some point. However, the mapping of points in the user coordinate space to pixels in the device coordinate space is normally handled by the system. Both UIKit and Core Graphics use a primarily vector-based drawing model where all coordinate values are specified using points. Thus, if you draw a curve using Core Graphics, you specify the curve using the same values, regardless of the resolution of the underlying screen.
在设备层面,有些时候,所有你在视图里指定的坐标都必须被转化为像素。 然而, 在设备坐标空间内映射用户坐标空间的点到像素的工作通常是由系统来完成的。 UIKit 和 Core Graphics(内核图形)都使用一个主要基于矢量的绘图模型,在那里所有的坐标值都是由点指定的。 因此, 如果你用内核图形绘制一条弧形,你只要给弧形指一个相同值,不用管底层屏幕的分辨率。
When you need to work with images or other pixel-based technologies such as OpenGL ES, iOS provides help in managing those pixels. For static image files stored as resources in your application bundle, iOS defines conventions for specifying your images at different pixel densities and for loading the image that best matches the current screen resolution. Views also provide information about the current scale factor so that you can adjust any pixel-based drawing code manually to accommodate higher-resolution screens. The techniques for dealing with pixel-based content at different screen resolutions is described in “Supporting High-Resolution Screens” in Drawing and Printing Guide for iOS.
当你的工作中需要使用图片或其它基于像素的技术(比如OpenGL ES)时,iOS帮助你管理那些像素。 对于在应用程序包里作为资源存储的静态图片文件, iOS定义了给图片指定不同像素密度的各种约定,这些约定还包括让图片以最接近当前屏幕分辨率的分辨率载入。视图还提供了有关当前缩放因子的信息,这样你就能手动调整任何基于像素的绘图来适应高分辨率屏幕。 在不同屏幕分辨率下处理基于像素的内容的各种技术在 Drawing and Printing Guide for iOS 的 “Supporting High-Resolution Screens” 里有详细描述。
The Runtime Interaction Model for Views
视图的运行时交互模型
Any time a user interacts with your user interface, or any time your own code programmatically changes something, a complex sequence of events takes place inside of UIKit to handle that interaction. At specific points during that sequence, UIKit calls out to your view classes and gives them a chance to respond on behalf of your application. Understanding these callout points is important to understanding where your views fit into the system. Figure 1-7 shows the basic sequence of events that starts with the user touching the screen and ends with the graphics system updating the screen content in response. The same sequence of events would also occur for any programmatically initiated actions.
任何时候当用户跟你的用户界面发生交互时, 或任何时候当你自己的代码在编程上改变一些东西时,UIKit框架内发生的一个复杂事件序列就是用来处理该交互的。 在序列的一个特殊的点, UIKit 框架召唤出你的视图类,给它们机会响应应用程序的行为。 理解这些召唤点对于理解你的视图在什么地方融入系统很重要。 图1-7显示了事件的基本序列,从用户触摸屏幕开始到图形系统更新屏幕内容响应事件结束。同样的事件序列在任何程序初始化操作时都会发生。
UIKit interactions with your view objects
图 1-7 UIKit 框架跟视图对象的交互
The following steps break the event sequence in Figure 1-7 down even further and explain what happens at each stage and how you might want your application to react in response.
下面的步骤更进一步的分析了 图1-7 中发生的事件, 解释了每一步发生的什么,以及你可能需要你的应用程序如何响应。
-
The user touches the screen.
用户触摸了屏幕。
-
The hardware reports the touch event to the UIKit framework.
硬件向UIKit 框架报告了该触摸事件。
-
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.)UIKit 框架把触摸事件打包进一个 UIEvent 对象, 并把它发派给相应的视图。(UIKit 如何传递事件到视图的详细解释,请看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.
改变视图或它的子视图的属性(frame , bounds, alpha, 等等)。
-
Call the
setNeedsLayout
method to mark the view (or its subviews) as needing a layout update.调用
setNeedsLayout 方法来标记该视图(或其子视图),作为一个需要更新的布局。
-
Call the
setNeedsDisplay
orsetNeedsDisplayInRect:
method to mark the view (or its subviews) as needing to be redrawn.调用
setNeedsDisplay
或setNeedsDisplayInRect: 方法来标记视图(或其子视图),作为需要被重新绘制。
-
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:
如果视图的几何外形因为任何原因发生了改变, UIKit 参照以下规则更新它的子框架:
-
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.”
如果你已经给你的视图设置了自动调整大小规则, UIKit 根据那些规则调整每个视图。 更多有关自动调整大小规则是如何工作的信息,请看“Handling Layout Changes Automatically Using Autoresizing Rules.”
-
If the view implements the
layoutSubviews
method, UIKit calls it.如果视图实现了
layoutSubviews 方法, UIKit 框架调用它。
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.
你可以在你的自定义视图里重载该方法, 并用它调整任何子视图的位置及大小。 比如, 一个提供大滚动区域的视图需要使用几个子视图作为瓦片(tiles), 而不是创建一个无论如何也不太可能适应内存的大视图。在该方法的实现中,视图可能隐藏任何现在不用显示的子视图,或者重新定位它们并使用它们去绘制新暴露的内容。作为该过程的一部分, 视图布局代码也可以让需要被重画的任何视图无效。
-
-
If any part of any view was marked as needing to be redrawn, UIKit asks the view to redraw itself.
如果任何视图的任何部分被标记为需要被重画, UIKit 要求视图重画它自己。
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.对于明确定义了一个
drawRect: 方法的自定义视图, UIKit 调用那个方法。 该方法的实现应该是尽可能快的重画视图的指定区域,而不做其它任何事情。 不要在该这时候做额外的布局改变, 也不要给应用程序数据模型做任何其它改变。 该方法的目的是更新视图的可见内容。
Standard system views typically do not implement a
drawRect:
method but instead manage their drawing at this time.标准系统视图通常不会实现一个drawRect:方法, 但是会在这时候管理它们的绘图。
-
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.
图形硬件在屏幕上绘制这些内容。
Note: The preceding update model applies primarily to applications that use standard system views and drawing techniques. Applications that use OpenGL ES for drawing typically configure a single full-screen view and draw directly to the associated OpenGL graphics context. In such a case, the view would still handle touch events but, because it is full-screen, it would not need to lay out subviews or implement a drawRect:
method. For more information about using OpenGL ES, see OpenGL ES Programming Guide for iOS.
注意: 先前的更新模型主要应用于使用标准系统视图以及绘图技术的应用程序。通常使用OpenGL ES来绘制的应用程序都配置了一个全屏视图, 并直接在相关的OpenGL图形上下文上绘制。 在这种情况下,视图可能任然需要处理触摸事件,但是因为它是全屏的,它可能不需要布局子视图或实现一个drawRect:方法。 更多使用OpenGL ES的信息,请看OpenGL ES Programming Guide for iOS.
In the preceding set of steps, the primary integration points for your own custom views are:
在前面的步骤中,你自定义视图的主要交互点是:
-
The event-handling methods:
事件处理方法:
-
The
layoutSubviews
methodlayoutSubviews 方法
-
The
drawRect:
methoddrawRect:方法
These are the most commonly overridden methods for views but you may not need to override all of them. If you use gesture recognizers to handle events, you do not need to override any of the event-handling methods. Similarly, if your view does not contain subviews or its size does not change, there is no reason to override the layoutSubviews
method. Finally, the drawRect:
method is needed only when the contents of your view can change at runtime and you are using native technologies such as UIKit or Core Graphics to do your drawing.
这些是视图最常重载的方法,但是你可能不需要全部重载。 如果你使用手势辨认器来处理事件,你就不需要重载任何一个事件处理方法。 同样地,如果你的视图不包含子视图或它的尺寸不会改变,也没有原因要重载layoutSubviews 方法。 最后, 当你的视图内容在运行时能发生改变时,drawRect:方法是你仅需重载的一个方法, 并且你使用本地技术,比如UIKit 或 Core Graphics 来完成绘图。
It is also important to remember that these are the primary integration points but not the only ones. Several methods of theUIView
class are designed to be override points for subclasses. You should look at the method descriptions in UIView Class Reference to see which methods might be appropriate for you to override in your custom implementations.
请记住这些方法是主要的交互点,但不是只有这些点才可以交互。 UIView的一些方法也可以被设计可以成为子类们的重载点(override points)。你应该在UIView Class Reference 里查看方法说明,查看它们哪些方法适合你在自定义实现里重载。
Tips for Using Views Effectively
高效使用视图的诀窍
Custom views are useful for situations where you need to draw something the standard system views do not provide, but it is your responsibility to ensure that the performance of your views is good enough. UIKit does everything it can to optimize view-related behaviors and help you achieve good performance in your custom views. However, you can help UIKit in this aspect by considering the following tips.
在你需要绘制一些标准系统视图不能提供的内容的情况下,自定义视图是很有用的,但是你必须负责确保你的视图性能已经足够好。 UIKit 做了一切它能做的来优化视图相关行为,并帮助你在你的自定义视图里实现好的性能。 但是, 你还可以通过考虑以下提示来优化UIKit的这方面。
Important: Before optimizing your drawing code, you should always gather data about your view’s current performance. Measuring the current performance lets you confirm whether there actually is a problem and, if there is, gives you a baseline measurement against which you can compare future optimizations.
重要:在你优化你的绘图代码前,你应该总是收集有关视图当前性能的数据。测量当前的性能让你确定是否确实存在问题,如果是,它还给你一个跟将来的优化进行比较的基线测量。
Views Do Not Always Have a Corresponding View Controller
一、视图不一定总有一个相应的视图控制器
There is rarely a one-to-one relationship between individual views and view controllers in your application. The job of a view controller is to manage a view hierarchy, which often consists of more than one view used to implement some self-contained feature. For iPhone applications, each view hierarchy typically fills the entire screen, although for iPad applications a view hierarchy may fill only part of the screen.
应用程序的独立视图和视图控制器之间很少存在一对一的关系。 视图控制器的工作是管理视图层次,视图层次常常有多个视图构成,它们被用来实现一些它们自己的功能。 对于iPhone应用程序,每个视图层次通常都装有整个屏幕,尽管对于iPad应用程序来说一个视图层次可能只装有屏幕的一部分。
As you design your application’s user interface, it is important to consider the role that view controllers will play. View controllers provide a lot of important behaviors, such as coordinating the presentation of views on the screen, coordinating the removal of those views from the screen, releasing memory in response to low-memory warnings, and rotating views in response to interface orientation changes. Circumventing these behaviors could cause your application to behave incorrectly or in unexpected ways.
当你设计你的用户界面时, 考虑视图控制器的角色很重要。 视图控制器提供了很多重要的行为, 比如协调在屏幕上的视图, 协调从屏幕移除的视图, 响应低内存警告释放内存, 以及响应界面方面变换事件旋转视图。 规避这些行为能导致应用程序行为错误或者以意想不到的方式行为。
For more information view controllers and their role in applications, see View Controller Programming Guide for iOS.
有关视图控制器以及它们在应用程序里所扮演的角色等的更多信息,请看View Controller Programming Guide for iOS.
Minimize Custom Drawing
二、最少化自定义绘图
Although custom drawing is necessary at times, it is also something you should avoid whenever possible. The only time you should truly do any custom drawing is when the existing system view classes do not provide the appearance or capabilities that you need. Any time your content can be assembled with a combination of existing views, your best bet is to combine those view objects into a custom view hierarchy.
尽管有时自定义绘图很必要,但是这也是任何时候你应该尽可能避免的事情。只有当存在的系统视图类确实无法满足你需要的外形或能力时,你才需要决定做一些自定义绘图。 任何时候如果你的内容可以通过已存在的视图组合获得,最好的解决方法就是把这些视图对象组合到一个自定义视图层次里。
Take Advantage of Content Modes
三、利用各种内容模式
Content modes minimize the amount of time spent redrawing your views. By default, views use theUIViewContentModeScaleToFill
content mode, which scales the view’s existing contents to fit the view’s frame rectangle. You can change this mode as needed to adjust your content differently, but you should avoid using theUIViewContentModeRedraw
content mode if you can. Regardless of which content mode is in effect, you can always force your view to redraw its contents by calling setNeedsDisplay
or setNeedsDisplayInRect:
.
内容模式能让你重画视图的总时间最小化。 默认情况下,视图使用UIViewContentModeScaleToFill 内容模式,该模式缩放视图现有的内容来填充视图的框架矩形。你可以根据需要改变该模式来对内容进行不同的调整, 但是如果可以,你应该避免使用UIViewContentModeRedraw 内容模式。不管哪个内容模式在起作用,你总是可以强制视图对内容进行重画,只要调用
setNeedsDisplay
或 setNeedsDisplayInRect:方法。
Declare Views as Opaque Whenever Possible
四、任何时候尽可能的声明不透明视图
UIKit uses the opaque
property of each view to determine whether the view can optimize compositing operations. Setting the value of this property to YES
for a custom view tells UIKit that it does not need to render any content behind your view. Less rendering can lead to increased performance for your drawing code and is generally encouraged. Of course, if you set the opaque
property to YES
, your view must fills its bounds rectangle completely with fully opaque content.
UIKit 使用视图的 opaque 属性来决定视图是否可以优化合成操作。 把自定义视图的opaque属性设置为YES,告诉UIKit不需要渲染在本视图后面的任何内容。更少的渲染能增强你的绘图代码性能,通常被鼓励使用。 当然,如果你把opaque属性设置为YES,视图必须全部用不透明内容来填满整个边界矩形。
Adjust Your View’s Drawing Behavior When Scrolling
五、在滚动时调整视图的绘制行为
Scrolling can incur numerous view updates in a short amount of time. If your view’s drawing code is not tuned appropriately, scrolling performance for your view could be sluggish. Rather than trying to ensure that your view’s content is pristine at all times, consider changing your view’s behavior when a scrolling operation begins. For example, you can reduce the quality of your rendered content temporarily or change the content mode while a scroll is in progress. When scrolling stops, you can then return your view to its previous state and update the contents as needed.
滚动能在很短的时间内发动多个视图更新。 如果没有适当的调整你的绘制代码, 视图的滚动性能会很慢。与其尝试确保你的视图内容始终都是最新的, 不如考虑当一个滚动操作开始时改变视图的行为。 比如, 你可以暂时的降低你的渲染内容的质量或者滚动时改变内容模式。当滚动停止后,你可以把视图返回到它的前一个状态,并根据需要更新内容。
Do Not Customize Controls by Embedding Subviews
六、不要通过嵌入子视图来定制控制
Although it is technically possible to add subviews to the standard system controls—objects that inherit from UIControl
—you should never customize them in this way. Controls that support customizations do so through explicit and well-documented interfaces in the control class itself. For example, the UIButton
class contains methods for setting the title and background images for the button. Using the defined customization points means that your code will always work correctly. Circumventing these methods, by embedding a custom image view or label inside the button, might cause your application to behave incorrectly now or at some point in the future if the button’s implementation changes.
尽管把子视图加入标准系统控制在技术上是可能的----继承自UIControl的对象----你绝不应该以这种方式自定义它们。支持定制的控制通过位于控制类自身内部的明确并有被很好记载的接口来实现。比如, UIButton类包含了给按钮设置标题和背景图片的方法。 使用定义的定制点(customization points)意味着你的代码将永远能正确工作。 通过在按钮里嵌入一个自定义图片视图或标签来规避(Circumventing)这些方法,如果按钮的实现改变时,可能导致应用程序立即或在将来的某个点发生行为错误。