天天看点

1102 - iOS◍ 文档: View Programming Guide for iOS -- iOS的视图编程指南 第三章 view Views

参考链接:https://www.cnblogs.com/patientAndPersist/p/3171311.html

别人翻译得很好了,后面的有一些我是直接复制粘贴的

Views

--Because view objects are the main way your application interacts with the user, they have many responsibilities. Here are just a few:

     view是客户与手机进行交互的主要方式,但是window才是传递事件的担当者。然后,一个view的主要职责有:

● Layout and subview management --布局和管理子view方面有:

  • A view defines its own default resizing behaviors in relation to its parent view.

       view定义自己的 相对于父视图的 默认的“尺寸调整行为”

  • A view can manage a list of subviews.

       view可以管理一堆子view

  • A view can override the size and position of its subviews as needed.

        view可以复写子 view的大小和位置。

  • A view can convert points in its coordinate system to the coordinate systems of other views or the window.

        view可以转换不同坐标系间的“点单元”

● Drawing and animation  -- 绘图与动画效果:

  • A view draws content in its rectangular area.

       view在自己的矩形中绘制内容

  • Some view properties can be animated to new values.

       view中的部分属性可以由一个值动画过渡到另一个值

● Event handling -- 事件处理

  • A view can receive touch events.

       view可以接受触摸事件

  • A view participates in the responder chain.

       view参与响应者链

--This chapter focuses on the steps for creating, managing, and drawing views and for handling the layout and management of view hierarchies. For information about how to handle touch events (and other events) in your views, see Event Handling Guide for iOS.

    这一章主要是讲view的创建、管理、绘制、布局处理以及视图层的管理。更多关于view中触摸事件的管理,搜索Event Handling Guide for iOS

Creating and Configuring View Objects -- 创建和配置view

--You create views as self-contained objects either programmatically or using Interface Builder, and then you assemble them into view hierarchies for use.

    IB或者编程方式

Creating View Objects Using Interface Builder -- 用IB创建view

--The simplest way to create views is to assemble them graphically using Interface Builder. From Interface Builder, you can add views to your interface, arrange those views into hierarchies, configure each view’s settings, and connect view-related behaviors to your code. Because Interface Builder uses live view objects—that is, actual instances of the view classes—what you see at design time is what you get at runtime. You then save those live objects in a nib file, which is a resource file that preserves the state and configuration of your objects.

      IB画出来的view是一个活着的view实例,所以你可以在画的时候就可以看到同样的在app运行期的效果。然后你是把这个view以nib file的形式存起来,然后app真正运行时就把这个view真实的复活出来 。

--You usually create nib files in order to store an entire view hierarchy for one of your application’s view controllers. The top level of the nib file usually contains a single view object that represents your view controller’s view. (The view controller itself is typically represented by the File’s Owner object.) The top-level view should be sized appropriately for the target device and contain all of the other views that are to be presented. It is rare to use a nib file to store only a portion of your view controller’s view hierarchy.

    每一个vc都管理自己的一个视图层次,而一个nib file 通常用来储存一个视图层次,而不是单单一个view。

--When using nib files with a view controller, all you have to do is initialize the view controller with the nib file information. The view controller handles the loading and unloading of your views at the appropriate times. However, if your nib file is not associated with a view controller, you can load the nib file contents manually using an

NSBundle

or

UINib

object, which use the data in the nib file to reconstitute your view objects.

     如果你的nib file和一个vc关联,那么vc负责从nib file上加载和卸载view。如果你没有与vc关联,那么你就可以使用

NSBundle

or

UINib

实例来从nib file中获取关于view的信息,然后将这些view的集合 复活

--For more information about how to use Interface Builder to create and configure your views, see Interface Builder User Guide. For information about how view controllers load and manage their associated nib files, see Creating Custom Content View Controllers in View Controller Programming Guide for iOS. For more information about how to load views programmatically from a nib file, see Nib Files in Resource Programming Guide.

     关于如何使用IB、vc如何与nib file关联加载卸载、如何从nib file中加载一个view、自己看对应的超链接

Creating View Objects Programmatically -- 编程方式创建view

--If you prefer to create views programmatically, you can do so using the standard allocation/initialization pattern. The default initialization method for views is the

initWithFrame:

method, which sets the initial size and position of the view relative to its (soon-to-be-established) parent view. For example, to create a new generic

UIView

object, you could use code similar to the following:

     allocation/initialization pattern.是实例的内存分配和初始化模式,可以打超链接看一下。view默认的初始化方法是

initWithFrame:

,你调用该初始化方法设置view在父view中的位置和尺寸。示例如下:

CGRect  viewRect = CGRectMake(0, 0, 100, 100);
UIView* myView = [[UIView alloc] initWithFrame:viewRect];
           

--Note: Although all views support the

initWithFrame:

method, some may have a preferred initialization method that you should use instead. For information about any custom initialization methods, see the reference documentation for the class.

     注意:

initWithFrame:

初始化方法是所有view都有的方法,但不是唯一的选择,有些view提供了更好的初始化方法,使用时考虑一下。

--After you create a view, you must add it to a window (or to another view in a window) before it can become visible. For information on how to add views to your view hierarchy, see Adding and Removing Subviews.

       在创建一个view之后,你必须把它直接或间接地添加到window里面,关于如何增删子view,看下面。

Setting the Properties of a View -- 设置一个view的属性

--The

UIView

class has several declared properties for controlling the appearance and behavior of the view. These properties are for manipulating the size and position of the view, the view’s transparency, its background color, and its rendering behavior. All of these properties have appropriate default values that you can change later as needed. You can also configure many of these properties from Interface Builder using the Inspector window.

      你可以通过UIVIew的声明属性来修改view的位置、透明度、背景颜色、和渲染行为。

--Table 3-1 lists some of the more commonly used properties (and some methods) and describes their usage. Related properties are listed together so that you can see the options you have for affecting certain aspects of the view.

      UIView的部分声明属性以及方法的使用。

Table 3-1  Usage of some key view properties

Properties Usage

alpha

,

hidden

,

opaque

不透明度,隐藏,是否不透明

--These properties affect the opacity of the view. The

alpha

and

hidden

properties change the view’s opacity directly.

  alpha

hidden属性,直接影响UIView的透明度

--The

opaque

property tells the system how it should composite your view. Set this property to

YES

if your view’s content is fully opaque and therefore does not reveal any of the underlying view’s content. Setting this property to

YES

improves performance by eliminating unnecessary compositing operations.

    设置遮光度paque为true可以提供渲染效率,因为这样当前view底下的view的组成操作会被取消。

bounds

,

frame

,

center

,

transform

边界,框架,中心点,形变
--These properties affect the size and position of the view. The

center

and

frame

properties represent the position of the view relative to its parent view. The

frame

also includes the size of the view. The

bounds

property defines the view’s visible content area in its own coordinate system.

   center

frame属性是以父视图的坐标为坐标系,bounds是自身的本地坐标系

--The

transform

property is used to animate or move the entire view in complex ways. For example, you would use a transform to rotate or scale the view. If the current transform is not the identity transform, the

frame

property is undefined and should be ignored.

For information about the relationship between the

bounds

,

frame

, and

center

properties, see The Relationship of the Frame, Bounds, and Center Properties. For information about how transforms affect a view, see Coordinate System Transformations.

    超链接看Frame, Bounds, and Center Properties属性的区别,Coordinate System Transformations.看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.

  autoresizingMask

属性控制view如何响应父view的bounds变化。

autoresizesSubviews属性控制view的子view是不是尺寸自动调整的。

contentMode

,

contentStretch

,

contentScaleFactor

内容模式、内容拉伸、内容缩放因子

--These properties affect the rendering behavior of content inside the view. The

contentMode

and

contentStretch

properties determine how the content is treated when the view’s width or height changes. The

contentScaleFactor

property is used only when you need to customize the drawing behavior of your view for high-resolution screens.

  contentMode 和 contentStretch属性用于视图内容如何响应view的宽高发生改变,

contentScaleFactor属性用于处理高分辨率屏幕的渲染view的行为。

--For more information on how the content mode affects your view, see Content Modes. For information about how the content stretch rectangle affects your view, see Stretchable Views. For information about how to handle scale factors, see Supporting High-Resolution Screens In Views in Drawing and Printing Guide for iOS.

     关于内容模式看Content Modes;关于view的拉伸,看Stretchable Views;关于高分辨率屏幕的缩放,看Drawing and Printing Guide for iOS中的Supporting High-Resolution Screens In Views。

gestureRecognizers

,

userInteractionEnabled

,

multipleTouchEnabled

,

exclusiveTouch

手势识别器、用户交互使能、多点触摸使能、专一触摸使能

--These properties affect how your view processes touch events. The

gestureRecognizers

property contains gesture recognizers attached to the view. The other properties control what touch events the view supports.

  gestureRecognizers属性用于关联手势识别器,其他属性也是触摸事件的相关支持。

--For information about how to respond to events in your views, see Event Handling Guide for iOS.

     关于触摸事件的响应,百度Event Handling Guide for iOS

backgroundColor

,

subviews

,

drawRect:

method,

layer

, (

layerClass

method)

背景颜色、子view、绘制矩形方法

--These properties and methods help you manage the actual content of your view. For simple views, you can set a background color and add one or more subviews. The

subviews

property itself contains a read-only list of subviews, but there are several methods for adding and rearranging subviews. For views with custom drawing behavior, you must override the

drawRect:

method.

  subviews属性返回的是一组子view列表,但是是只读的,你可以复写drawRect:来自定义视图的绘制行为。

--For more advanced content, you can work directly with the view’s Core Animation

layer

. To specify an entirely different type of layer for the view, you must override the

layerClass

method.

   动画属性的相关设置,你必须要复写layer类里面的相关方法。

--For information about the basic properties common to all views, see UIView Class Reference. For more information about specific properties of a view, see the reference documentation for that view.

Tagging Views for Future Identification -- 给view加标签 供查找子view使用

--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

.

   UIView有一

个tag属性,你可以赋值整数值给该属性,来唯一标识一个view实例。这样寻找views层中的某一个view时,效率比遍历整个views层要高。

--To search for a tagged view, use the

viewWithTag:

method of

UIView

. This method performs a depth-first search of the receiver and its subviews. It does not search superviews or other parts of the view hierarchy. Thus, calling this method from the root view of a hierarchy searches all views in the hierarchy but calling it from a specific subview searches only a subset of views.

    使用UIView中的

viewWithTag:

方法来获取子views数组中带有某tag的子view,这是用深度搜索算法实现的。

Creating and Managing a View Hierarchy -- 创建和管理视图层

--Managing view hierarchies is a crucial part of developing your application’s user interface. The organization of your views influences both the visual appearance of your application and how your application responds to changes and events. For example, the parent-child relationships in the view hierarchy determine which objects might handle a specific touch event. Similarly, parent-child relationships define how each view responds to interface orientation changes.

      视图的组织既影响了app可见的外观,也影响了你的app如何响应事件以及app状态的变化。例如父子关系中,就可以指定某object处理某触摸事件。

--Figure 3-1 shows an example of how the layering of views creates the desired visual effect for an application. In the case of the Clock application, the view hierarchy is composed of a mixture of views derived from different sources. The tab bar and navigation views are special view hierarchies provided by the tab bar and navigation controller objects to manage portions of the overall user interface. Everything between those bars belongs to the custom view hierarchy that the Clock application provides.

     图 3-1 显示了”视图的分层机制“如何创建应用app所需的视图效果。在时钟app中,视图的层次结构是由不同来源的各种视图的混合物组成的。标签栏和导航视图是特殊的视图层次结构, 它们由标签栏和导航控制器对象提供,用来管理整个用户界面的一部分。你可以在标签栏里自定义你的视图层,而这种结构的支持,由时钟app提供。

Figure 3-1  Layered views in the Clock application

1102 - iOS◍ 文档: View Programming Guide for iOS -- iOS的视图编程指南 第三章 view Views

--There are several ways to build view hierarchies in iOS 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.

      在iOS应用程序里有好几种方式可以建立视图层次结构,包括在IB里的图形化设计和在代码实现。接下来的章节显示你可以如何合成视图层次结构,以及当你完成层次后如何在层次结构里查找这些视图,以及如何在不同坐标系统里互相转换。

Adding and Removing Subviews -- 添加和删除子视图

--Interface Builder is the most convenient way to build view hierarchies because you assemble your views graphically, see the relationships between the views, and see exactly how those views will appear at runtime. When using Interface Builder, you save your resulting view hierarchy in a nib file, which you load at runtime as the corresponding views are needed.

     使用IB创建视图层次,你的view 层次是存储在nib file里面的,nib file是在运行期按需加载的。

--If you prefer to create your views programmatically instead, you create and initialize them and then use the following methods to arrange them into hierarchies:

     编程方式创建view 层次的话,你需要用到以下方法:

  • 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.

       在父view 中调用

addSubview:

方法来创建子view,并自动添加到view层次中了

  • To insert a subview in the middle of the parent’s list of subviews, call any of the

    insertSubview:...

    methods of the parent view. Inserting a subview in the middle of the list visually places that view behind any views that come later in the list.

       想在父视图的子视图列表中部插入一个子视图,你可以调用

insertSubview:...

方法;然后该子视图就会出现子视图列表的中间了。    

  • To reorder existing subviews inside their parent, call the

    bringSubviewToFront:

    ,

    sendSubviewToBack:

    , or

    exchangeSubviewAtIndex:withSubviewAtIndex:

    methods of the parent view. Using these methods is faster than removing the subviews and reinserting them.

       想要重排序子视图的位置,那么你可以调用父视图的

bringSubviewToFront:

,

sendSubviewToBack:

, 和

exchangeSubviewAtIndex:withSubviewAtIndex:

方法,就会执行把子视图放在最前、最后、交换位置的操作,这比插入、删除子视图的效率要高。

  • To remove a subview from its parent, call the

    removeFromSuperview

    method of the subview (not the parent view).

        从父视图中移除子视图,是调用子视图的

removeFromSuperview

方法,注意是子视图的方法,不是父视图。

--When adding a subview to its parent, the subview’s current frame rectangle denotes its initial position inside the parent view. A subview whose frame lies outside of its superview’s visible bounds is not clipped by default. If you want your subview to be clipped to the superview’s bounds, you must explicitly set the

clipsToBounds

property of the superview to

YES

.

     当添加一个子视图到父视图中时,子视图的frame是参考父视图的frame的坐标系的。而且,默认是不裁剪子视图内容来适应父视图的bounds边界的。你可以使用父视图的

clipsToBounds

属性为true,来使子视图裁剪适应。

--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.

     一般来讲,编程方式添加子视图,是在vc的

loadView

viewDidLoad

方法中写添加代码的。

Listing 3-1 shows the

viewDidLoad

method of the

TransitionsViewController

class from the UIKit Catalog (iOS): Creating and Customizing UIKit Controls sample application. The

TransitionsViewController

class manages the animations associated with transitioning between two views. The application’s initial view hierarchy (consisting of a root view and toolbar) is loaded from a nib file. The code in the

viewDidLoad

method subsequently creates the container view and image views used to manage the transitions. The purpose of the container view is to simplify the code needed to implement the transition animations between the two image views. The container view has no real content of its own.

    列表3-1的代码来自于超链接UIKit Catalog (iOS): Creating and Customizing UIKit Controls的示例中的部分代码,是例子中的

TransitionsViewController的部分代码,展示在

viewDidLoad

方法中添加子视图到父视图中的关键代码。

示例实现了两个view之间的动画过渡效果。

   示例中的

TransitionsViewController是一个vc容器,由根视图和工具栏组成。

 容器视图的作用主要是为了简化两个子view之间动画过渡时的代码。

Listing 3-1  Adding views to an existing view hierarchy

                       示例代码展示如何添加现存view到视图层次里面

- (void)viewDidLoad

{
    [super viewDidLoad];

    self.title = NSLocalizedString(@"TransitionsTitle", @"");

    // create the container view which we will use for transition animation (centered horizontally)

    CGRect frame = CGRectMake(round((self.view.bounds.size.width - kImageWidth) / 2.0), kTopPlacement, kImageWidth, kImageHeight);

    self.containerView = [[[UIView alloc] initWithFrame:frame] autorelease];

    [self.view addSubview:self.containerView];

    // The container view can represent the images for accessibility.

    [self.containerView setIsAccessibilityElement:YES];

    [self.containerView setAccessibilityLabel:NSLocalizedString(@"ImagesTitle", @"")];

    // create the initial image view

    frame = CGRectMake(0.0, 0.0, kImageWidth, kImageHeight);

    self.mainView = [[[UIImageView alloc] initWithFrame:frame] autorelease];

    self.mainView.image = [UIImage imageNamed:@"scene1.jpg"];

    [self.containerView addSubview:self.mainView];

    // create the alternate image view (to transition between)

    CGRect imageFrame = CGRectMake(0.0, 0.0, kImageWidth, kImageHeight);

    self.flipToView = [[[UIImageView alloc] initWithFrame:imageFrame] autorelease];

    self.flipToView.image = [UIImage imageNamed:@"scene2.jpg"];

}
           

--Important: Superviews automatically retain their subviews, so after embedding a subview it is safe to release that subview. In fact, doing so is recommended because it prevents your application from retaining the view one time too many and causing a memory leak later. Just remember that if you remove a subview from its superview and intend to reuse it, you must retain the subview again. The

removeFromSuperview

method autoreleases a subview before removing it from its superview. If you do not retain the view before the next event loop cycle, the view will be released.

  移除子view的时候,记得释放子视图的资源,但是现在swift已经自动释放了。

--For more information about Cocoa memory management conventions, see Advanced Memory Management Programming Guide.

   更多关于内存管理的内容,参考超链接

--When you add a subview to another view, UIKit notifies both the parent and child views of the change. If you implement custom views, you can intercept these notifications by overriding one or more of the

willMoveToSuperview:

,

willMoveToWindow:

,

willRemoveSubview:

,

didAddSubview:

,

didMoveToSuperview

, or

didMoveToWindow

methods. You can use these notifications to update any state information related to your view hierarchy or to perform additional tasks.

     当你添加一个子view到父view中时,UIKit会同时通知父view和子view该“添加”事件。所以你可以在你的子类化view中复写view的

willMoveToSuperview:

,

willMoveToWindow:

,

willRemoveSubview:

,

didAddSubview:

,

didMoveToSuperview

, or

didMoveToWindow

这些方法之一,然后就可以在添加期间的响应时期做相关的操作。

--After creating a view hierarchy, you can navigate it programmatically using the

superview

and

subviews

properties of your views. The

window

property of each view contains the window in which that view is currently displayed (if any). Because the root view in a view hierarchy has no parent, its

superview

property is set to

nil

. For views that are currently onscreen, the window object is the root view of the view hierarchy.

     创建完一个视图层次结构之后,你可以通过程序使用视图的 

superview

 和 

subviews 属性来使用它。每个视图的 

window 属性包含了该窗口,窗口里显示当前的所有视图(如果有)。因为视图层次结构里的根视图没有父视图,它的superview属性被设置为nil. 对于那些正在屏幕上的所有视图,窗口对象是该视图层次结构里的根视图。

Hiding Views -- 隐藏视图

--To hide a view visually, you can either set its

hidden

property to

YES

or change its

alpha

property to

0.0

. A hidden view does not receive touch events from the system. However, hidden views do participate in autoresizing and other layout operations associated with the view hierarchy. Thus, hiding a view is often a convenient alternative to removing views from your view hierarchy, especially if you plan to show the views again at some point soon.

      隐藏的view不接收事件的传递,但是仍然参与自动布局。

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, see Event Handling Guide for iOS.

        view即便隐藏了,也不会修改自己第一响应者的身份,所以你要手动修改。

--If you want to animate a view’s transition from visible to hidden (or the reverse), you must do so using the view’s

alpha

property. The

hidden

property is not an animatable property, so any changes you make to it take effect immediately.

hidden

属性没有动画效果,

alpha

属性有动画效果

Locating Views in a View Hierarchy -- 定位视图层中的视图

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

两个方法定位视图,一是直接创建时复制引用,二是用view的tag标签,可以两者并用。

  • 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.

--Storing references to relevant views is the most common approach to locating views and makes accessing those views very convenient. If you used Interface Builder to create your views, you can connect objects in your nib file (including the File’s Owner object that represents the managing controller object) to one another using outlets. For views you create programmatically, you can store references to those views in private member variables. Whether you use outlets or private member variables, you are responsible for retaining the views as needed and then releasing them as well. The best way to ensure objects are retained and released properly is to use declared properties.

     建议将子view声明为私有属性。

--Tags are a useful way to reduce hard-coded dependencies and support more dynamic and flexible solutions. Rather than storing a pointer to a view, you could locate it using its tag. Tags are also a more persistent way of referring to views. For example, if you wanted to save the list of views that are currently visible in your application, you would write out the tags of each visible view to a file. This is simpler than archiving the actual view objects, especially in situations where you are tracking only which views are currently visible. When your application is subsequently loaded, you would then re-create your views and use the saved list of tags to set the visibility of each view, and thereby return your view hierarchy to its previous state.

    使用tag来寻找view有助于提供性能。

Translating, Scaling, and Rotating Views -- 转换、缩放、和旋转视图

--Every view has an associated affine transform that you can use to translate, scale, or rotate the view’s content. View transforms alter the final rendered appearance of the view and are often used to implement scrolling, animations, or other visual effects.

       形变最终会改变view的外观。

The

transform

property of

UIView

contains a

CGAffineTransform

structure with the transformations to apply. By default, this property is set to the identity transform, which does not modify the appearance of the view. You can assign a new transform to this property at any time. For example, to rotate a view by 45 degrees, you could use the following code:

      形变必须是恒等变换,数学上的知识,形变的值是

CGAffineTransform

结构体里面的值,下面是形变的简单示例代码:

// M_PI/4.0 is one quarter of a half circle, or 45 degrees.

CGAffineTransform xform = CGAffineTransformMakeRotation(M_PI/4.0);

self.view.transform = xform;
           

--Applying the transform in the preceding code to a view would rotate that view clockwise about its center point. Figure 3-2 shows how this transformation would look if it were applied to an image view embedded in an application.

        给视图应用以上代码的变换可以将视图围绕它的中心点旋转45度。图3-2 显示了该变换应用于形变视图的效果。

Figure 3-2  Rotating a view 45 degrees

1102 - iOS◍ 文档: View Programming Guide for iOS -- iOS的视图编程指南 第三章 view Views

--When applying multiple transformations to a view, the order in which you add those transformations to the

CGAffineTransform

structure is significant. Rotating the view and then translating it is not the same as translating the view and then rotating it. Even if the amounts of rotation and translation are the same in each case, the sequence of the transformations affects the final results. In addition, any transformations you add are applied to the view relative to its center point. Thus, applying a rotation factor rotates the view around its center point. Scaling a view changes the width and height of the view but does not change its center point.

      组合

CGAffineTransform

结构体的值的顺序不同,那么形变的效果也不一样。

--For more information about creating and using affine transforms, see Transforms in Quartz 2D Programming Guide.

     更多关于形变的信息,参考超链接。

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 report the location of each touch in the window’s coordinate system but view objects often need that information in the view’s local coordinate system. The

UIView

class defines the following methods for converting coordinates to and from the view’s local coordinate system:

     在不同的事件,特别是当处理事件时,应用程序可能需要转换坐标值,从一个框架引用到另一个。 比如,触摸事件报告的是每个触摸在窗口坐标系统里的位置,但是视图对象常常需要该位置在视图的内部坐标系统中的值。 UIView 类定义了以下方法,用来从视图的内部坐标系统转换坐标或从别的坐标系统转换到视图的内部坐标系统:

  • convertPoint:fromView:

  • convertRect:fromView:

  • convertPoint:toView:

  • convertRect:toView:

--The

convert...:fromView:

methods convert coordinates from some other view’s coordinate system to the local coordinate system (bounds rectangle) of the current view. Conversely, the

convert...:toView:

methods convert coordinates from the current view’s local coordinate system (bounds rectangle) 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.

      convert...:fromView: 方法把其它视图坐标系的坐标转换为当前视图的内部坐标系(边界矩形)坐标。相反,convert...:toView:方法则把当前坐标系坐标转换为其他的视图坐标系坐标。 如果你给任何方法指定了nil值作为引用视图,该转换是包含该视图的窗口坐标系统中转换而来,或者是转换到该窗口坐标系统中去。

--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.

      除了UIView 转换方法,UIWindow 类也定义了一些转换方法。这些方法跟UIView的方法相似,只除了这些方法是从窗口坐标系统中转换而来,或者转换到窗口坐标系统中去。

  • convertPoint:fromWindow:

  • convertRect:fromWindow:

  • convertPoint:toWindow:

  • convertRect:toWindow:

--When converting coordinates in rotated views, UIKit converts rectangles under the assumption that you want the returned rectangle to reflect the screen area covered by the source rectangle. Figure 3-3 shows an example of how rotations can cause the size of the rectangle to change during a conversion. In the figure, an outer parent view contains a rotated subview. Converting a rectangle in the subview’s coordinate system to the parent’s coordinate system yields a rectangle that is physically larger. This larger rectangle is actually the smallest rectangle in the bounds of

outerView

that completely encloses the rotated rectangle.

     当你在被旋转的视图里转换坐标时,UIKit在这样的假设下转换前的矩形---假设你想要返回的矩形反映了被源矩形覆盖的屏幕区域。图3-3 显示了一个例子---在转换过程中旋转如何导致矩形尺寸的改变。在图中,一个外部父视图包含了一个已旋转的子视图。转换在子视图坐标系统里的一个子视图到父视图坐标系统,生成了一个外形上更大的矩形。该被放大的矩形实际上是在外部视图(outerView)边界里完全包含被旋转矩形的最小矩形。

Figure 3-3  Converting values in a rotated view

1102 - iOS◍ 文档: View Programming Guide for iOS -- iOS的视图编程指南 第三章 view Views

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.

    无论何时一个视图的尺寸发生了改变,它的子视图的尺寸和位置也必须相应的发生改变。

UIView 类同时支持在一个视图层次结构里的视图的自动和手动布局。

 在自动布局里,你可以这样设置规则:每个视图,当它的父视图重新调整尺寸时,也跟着改变,然后儿子们全都忽略关于重新调整尺寸的操作。对于手动布局,你根据需要手动调整视图的尺寸和位置。

Being Prepared for Layout Changes -- 为布局的改变做准备

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

    如果发生以下事件,则可以引起视图布局的改变

  • The size of a view’s bounds rectangle changes.

        bounds矩形的尺寸改变

  • An interface orientation change occurs, which usually triggers a change in the root view’s bounds rectangle.

        设备方位的改变

  • 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.

        你通过调用

setNeedsLayout

or

layoutIfNeeded

方法强行将布局改变

  • Your application forces layout by calling the

    setNeedsLayout

    method of the view’s underlying layer object.

     你可以调用view的底层的layer的

    setNeedsLayout

    方法来强制app更新布局。

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.

    当你改变了视图的尺寸,所有子视图通常都需要改变他们的位置和尺寸,以适应它们父视图的新尺寸。 父视图的 

autoresizesSubviews 属性决定了子视图是否需要重新调整尺寸。 如果该属性被设置为YES, 视图使用每个子视图的autoresizingMask 属性来决定如何调整该子视图的尺寸和位置。 任何子视图的尺寸发生改变同时又触发它们的子视图也跟着改变以适应变化。

--For each view in your view hierarchy, setting that view’s

autoresizingMask

property to an appropriate value is an important part of handling automatic layout changes. Table 3-2 lists the autoresizing options you can apply to a given view and describes their effects during layout operations. You can combine constants using an OR operator or just add them together before assigning them to the

autoresizingMask

property. If you are using Interface Builder to assemble your views, you use the Autosizing inspector to set these properties.

    对于视图层次结构里的每个视图,给子view的 autoresizingMask 属性设置一个合适的值是处理自动布局改变的一个很重要的部分。你可以使用OR运算符组合这些常量或只需要在把它们发送给autoresizingMask属性之前把它们加到一起。如果你使用界面生成器来组合(assemble)你的视图,你可以使用Autosizing inspector 来设置这些属性。

Table 3-2  Autoresizing mask constants

Autoresizing mask Description

UIViewAutoresizingNone

----The view does not autoresize. (This is the default value.)

视图不会自动调整尺寸(这是默认值)

UIViewAutoresizingFlexibleHeight

--The view’s height changes when the superview’s height changes. If this constant is not included, the view’s height does not change.

当父视图的高度发生改变时,视图的高度也跟着改变。

UIViewAutoresizingFlexibleWidth

--The view’s width changes when the superview's width changes. If this constant is not included, the view’s width does not change.

当父视图的宽度发生改变时,子视图的宽度也发生改变。

UIViewAutoresizingFlexibleLeftMargin

--The distance between the view’s left edge and the superview’s left edge grows or shrinks as needed. If this constant is not included, the view’s left edge remains a fixed distance from the left edge of the superview.

视图左边缘和父视图的左边缘之间的距离根据需要放大或缩小。如果不包含该常量,视图的左边缘跟父视图的左边缘之间的距离保持一个固定值。

UIViewAutoresizingFlexibleRightMargin

--The distance between the view’s right edge and the superview’s right edge grows or shrinks as needed. If this constant is not included, the view’s right edge remains a fixed distance from the right edge of the superview.

视图右边缘和父视图的右边缘之间的距离根据需要放大或缩小。如果不包含该常量,视图的右边缘跟父视图的右边缘之间的距离保持一个固定值。

UIViewAutoresizingFlexibleBottomMargin

--The distance between the view’s bottom edge and the superview’s bottom edge grows or shrinks as needed. If this constant is not included, the view’s bottom edge remains a fixed distance from the bottom edge of the superview.

视图下边缘和父视图的下边缘之间的距离根据需要放大或缩小。如果不包含该常量,视图的下边缘跟父视图的下边缘之间的距离保持一个固定值。

UIViewAutoresizingFlexibleTopMargin

--The distance between the view’s top edge and the superview’s top edge grows or shrinks as needed. If this constant is not included, the view’s top edge remains a fixed distance from the top edge of the superview.

视图上边缘和父视图的上边缘之间的距离根据需要放大或缩小。如果不包含该常量,视图的上边缘跟父视图的上边缘之间的距离保持一个固定值。

--Figure 3-4 shows a graphical representation of how the options in the autoresizing mask apply to a view. The presence of a given constant indicates that the specified aspect of the view is flexible and may change when the superview’s bounds change. The absence of a constant indicates that the view’s layout is fixed in that aspect. When you configure a view that has more than one flexible attribute along a single axis, UIKit distributes any size changes evenly among the corresponding spaces.

      图3-4 显示了这些自动调整尺寸蒙板(autoresizing mask)应用于视图之后的图形化效果。下面给出的常量,表明视图的这方面是灵活的并可能在父视图边界发生变化时跟着改变。没有给出的常量表明视图的布局在这方面是固定的。当你沿着一个单轴(single axis)配置拥有多个灵活的属性的视图时,UIKit把所有的尺寸变化均匀地分布在相关空间里。

Figure 3-4  View autoresizing mask constants

1102 - iOS◍ 文档: View Programming Guide for iOS -- iOS的视图编程指南 第三章 view Views

--The easiest way to configure autoresizing rules is using the Autosizing controls in the Size inspector of Interface Builder. The flexible width and height constants from the preceding figure have the same behavior as the width and size indicators in the Autosizing controls diagram. However, the behavior and use of margin indicators is effectively reversed. In Interface Builder, the presence of a margin indicator means that the margin has a fixed size and the absence of the indicator means the margin has a flexible size. Fortunately, Interface Builder provides an animation to show you how changes to the autoresizing behaviors affect your view.

         配置自动调整尺寸最简单的方法是使用IB界面生成器中Size inspector的Autosizing controls项。上图中灵活的长宽常量跟在Autosizing controls图中的width and size indicators 有着相同的行为。然而, margin indicators的行为和使用却相反。在界面生成器里,margin indicator的存在表明一个固定值,不存在该值则表明margin有一个灵活的值。 幸运的是,界面生成器提供了一个动画,用来给你显示如何改变autoresizing 行为才会对你的视图产生影响。

Important: If a view’s

transform

property does not contain the identity transform, the frame of that view is undefined and so are the results of its autoresizing behaviors.

        如果视图的transform 属性值不是恒等变换,该视图的frame是未定义的,而且它的自动调整尺寸行为的结果也是未定义的。

--After the automatic autoresizing rules for all affected views have been applied, UIKit goes back and gives each view a chance to make any necessary manual adjustments to its superview. For more information about how to manage the layout of views manually, see Tweaking the Layout of Your Views Manually.

        当对所有被影响的视图应用自动调整尺寸规则之后,UIKit返回每个视图并给一个机会来 针对其父视图变化 做必要的手动调整。关于如何手动管理视图的布局的更多信息,请看“Tweaking the Layout of Your Views Manually.”

Tweaking the Layout of Your Views Manually -- 手动调整视图的布局

--Whenever the size of a view changes, UIKit applies the autoresizing behaviors of that view’s subviews and then calls the

layoutSubviews

method of the view to let it make manual changes. You can implement the

layoutSubviews

method in custom views when the autoresizing behaviors by themselves do not yield the results you want. Your implementation of this method can do any of the following:

       任何时候当view的尺寸发生变化时,UIKit都会给view的子视图应用自动调整尺寸行为,然后调用视图的 ★ layoutSubviews方法来让它做手动改变。当它们的自动调整尺寸行为不能产生你想要的结构时,你可以在自定义的视图里实现layoutSubviews方法。你对该方法的实现可以完成以下任何事情:

  • Adjust the size and position of any immediate subviews.

         调整任何当前的子视图的尺寸和位置。

  • Add or remove subviews or Core Animation layers.

         添加或删除子视图或内核动画层。

  • Force a subview to be redrawn by calling its

    setNeedsDisplay

    or

    setNeedsDisplayInRect:

    method.

       通过调用自己的

setNeedsDisplay

 或 

setNeedsDisplayInRect: 方法来强制子视图重新绘制。

--One place where applications often lay out subviews manually is when implementing a large scrollable area. Because it is impractical to have a single large view for its scrollable content, applications often implement a root view that contains a number of smaller tile views. Each tile represents a portion of the scrollable content. When a scroll event happens, the root view calls its

setNeedsLayout

method to initiate a layout change. Its

layoutSubviews

method then repositions the tile views based on the amount of scrolling that occurred. As tiles scroll out of the view’s visible area, the

layoutSubviews

method moves the tiles to the incoming edge, replacing their contents in the process.

       应用程序常常手动布局子视图的地方是当你实现一个大的可滚动区域时。因为只给它的滚动区域设置一个大的单一视图是不切实际的,应用程序常常实现一个根视图,在根视图里包含一定数量的较小的瓷砖(tile)视图。每个瓷砖代表可滚动内容的一部分。 当一个滚动事件发生时,根视图调用它的setNeedsLayout 方法来初始化一个布局改变。 然后它的layoutSubviews方法在发生的滚动数量基础上重新定位这些瓷砖视图。 当瓷砖滚出了视图的可见区域时,layoutSubviews方法把这些瓷砖移到进入的边缘,在进程中替换它们的内容。

--When writing your layout code, be sure to test your code in the following ways:

     当你编写你的布局代码时,请确保你的代码通过了以下测试:

  • Change the orientation of your views to make sure the layout looks correct in all supported interface orientations.

        改变你的视图方向,确保布局在所有支持的界面方向上都显示正确。

  • Make sure your code responds appropriately to changes in the height of the status bar. When a phone call is active, the status bar height increases in size, and when the user ends the call, the status bar decreases in size.

       确保你的代码能对状态栏高度的变化做出适当的响应。 当有来电时,状态栏高度尺寸增大,当用户切断通话时,状态栏缩减它的尺寸。

For information about how autoresizing behaviors affect the size and position of your views, see Handling Layout Changes Automatically Using Autoresizing Rules. For an example of how to implement tiling, see the ScrollViewSuite sample.

       关于自定调整尺寸行为如何影响视图的尺寸和位置的信息,请看“Handling Layout Changes Automatically Using Autoresizing Rules.” 关于如何实现tiling的例子,请看ScrollViewSuite。

Modifying Views at Runtime -- 在运行期修改视图

--As applications receive input from the user, they adjust their user interface in response to that input. An application might modify its views by rearranging them, changing their size or position, hiding or showing them, or loading an entirely new set of views. In iOS applications, there are several places and ways in which you perform these kinds of actions:

      当应用程序接收到用户输入时,会调整用户界面来响应那个输入。应用程序可能通过重新整理,改变界面的尺寸或位置,隐藏或显示界面,或载入一个完整的视图新集来修改界面上的视图。在iOS应用程序中,有很多地方和很多方法可以让你执行这类操作:

--In a view controller:

 在视图控制器中修改:

  • A view controller has to create its views before showing them. It can load the views from a nib file or create them programmatically. When those views are no longer needed, it disposes of them.

       视图控制器必须在显示view之前创建view。它能从一个nib文件载入视图,或者通过程序创建它们。当这些视图不再被需要时,vc要负责丢弃它们

  • When a device changes orientations, a view controller might adjust the size and position of views to match. As part of its adjustment to the new orientation, it might hide some views and show others.

       当设备改变方向时,视图控制器可能调整视图的尺寸和位置来匹配该方向。为了应对新方向做出调整,vc可能隐藏一些视图和显示一些其它视图。

  • When a view controller manages editable content, it might adjust its view hierarchy when moving to and from edit mode. For example, it might add extra buttons and other controls to facilitate editing various aspects of its content. This might also require the resizing of any existing views to accommodate the extra controls.

        当视图控制器管理一个可编辑内容时,当移入或移出编辑模式时,vc可能调整它的视图层次结构。比如,vc可能添加额外的按钮和其它一些控件来方便编辑vc内容的各个方面。 这样也可能要求对 任何已经存在的视图 做出尺寸调整,以容纳额外的控件。

--In animation blocks:

在动画块中修改:

  • When you want to transition between different sets of views in your user interface, you hide some views and show others from inside an animation block.

       当你想要在用户界面上的不同视图集之间互相过渡时,你可以在一个动画块里隐藏一些视图和显示其它视图。

  • When implementing special effects, you might use an animation block to modify various properties of the view. For example, to animate changes to the size of a view, you would change the size of its frame rectangle.

       当你想实现一些特殊效果时,你可能需要使用一个动画块来修改视图中的各种属性。比如,动画视图的尺寸变化,你也可能改变view的矩形和尺寸。

--Other ways:

其它方式修改: 

  • When touch events or gestures occur, your interface might respond by loading a new set of views or changing the current set of views. For information about handling events, see Event Handling Guide for iOS.

        当触摸事件或手势发生时,你的界面可以通过载入一个新的视图集或改变当前的视图集来响应。 关于处理事件的信息,请看Event Handling Guide for iOS.

  • When the user interacts with a scroll view, a large scrollable area might hide and show tile subviews. For more information about supporting scrollable content, see Scroll View Programming Guide for iOS.

       当用户跟一个滚动视图交互时,一个巨大的可滚动区可能隐藏,并显示瓷砖子视图。关于支持可滚动内容的更多信息,请看Scroll View Programming Guide for iOS.

  • When the keyboard appears, you might reposition or resize views so that they do not lie underneath the keyboard. For information about how to interact with the keyboard, see Text Programming Guide for iOS.
  •  当键盘出现时,你可能对视图做重新定位和定尺寸,这样它们在不会被隐藏在键盘下面。 关于如何跟键盘交互的信息,请看Text, Web, and Editing Programming Guide for iOS。

--View controllers are a common place to initiate changes to your views. Because a view controller manages the view hierarchy associated with the content being displayed, it is ultimately responsible for everything that happens to those views. When loading its views or handling orientation changes, the view controller can add new views, hide or replace existing ones, and make any number of changes to make the views ready for the display. And if you implement support for editing your view’s content, the

setEditing:animated:

method in

UIViewController

gives you a place to transition your views to and from their editable versions.

    视图控制器是开始改变视图的一个常用的地方。因为一个视图控制器管理着视图层次,该层次跟要显示的内容相关联,它最终负责对那些视图发生的所有事情。 当载入vc的视图或处理方向变换时,视图控制器能添加新视图,隐藏或替换存在的视图,并对准备显示的视图做任何数量的改变。 并且如果你实现支持可编辑视图的内容, UIViewController里的

setEditing:animated: 方法给你提供了一个地方,让你的视图从它们可编辑版本中过渡过来,或从可编辑版本过渡到视图中去。

--Animation blocks are another common place to initiate view-related changes. The animation support built into the

UIView

class makes it easy to animate changes to view properties. You can also use the

transitionWithView:duration:options:animations:completion:

or

transitionFromView:toView:duration:options:completion:

methods to swap out entire sets of views for new ones.

      动画块是开始做视图相关改变的另一个常用地方。 支持在

UIView类里内建动画让动画视图属性的各种改变变得容易。你还可以使用

transitionWithView:duration:options:animations:completion: 或 

transitionFromView:toView:duration:options:completion: 方法来给新的视图集合换出整个视图集合。

--For more information about animating views and initiating view transitions, see Animations. For more information on how you use view controllers to manage view-related behaviors, see View Controller Programming Guide for iOS.

    关于动画视图和初始化视图过渡的更多信息,请看 “Animations.” 关于你如何使用视图控制器来管理视图相关的行为的更多信息,请看View Controller Programming Guide for iOS.

Interacting with Core Animation Layers -- 与视图动画层交互

--Each view object has a dedicated Core Animation layer that manages the presentation and animation of the view’s content on the screen. Although you can do a lot with your view objects, you can also work directly with the corresponding layer objects as needed. The layer object for the view is stored in the view’s

layer

property.

    每个视图对象都有一个专用的内核动画层,该动画层管理屏幕上视图内容的呈现和动画。 尽管你可以用视图对象完成很多事情,你也可以根据需要直接跟相关的层对象一起工作。 视图的图层对象被存储在视图的

layer 属性里。

Changing the Layer Class Associated with a View -- 改变与视图相关的图层

--The type of layer associated with a view cannot be changed after the view is created. Therefore, each view uses the

layerClass

class method to specify the class of its layer object. The default implementation of this method returns the

CALayer

class and the only way to change this value is to subclass, override the method, and return a different value. You can change this value to use a different kind of layer. For example, if your view uses tiling to display a large scrollable area, you might want to use the

CATiledLayer

class to back your view.

      跟视图相关联的层类型在视图被创建后就不能被更改。 因此,每次视图使用layerClass 类方法来指定图层对象的类。该方法的默认实现返回

CALayer 类,而且改变该值的唯一方法是子类化UIView,重载该方法,并返回一个不同值。你可以使用不同的layer类型来赋值给

layerClass

属性,例如你想要大的滑动视图时,赋值CATiledLayer给你的view的

layerClass

属性即可。

Implementation of the

layerClass

method should simply create the desired

Class

object and return it. For example, a view that uses tiling would have the following implementation for this method:

     实现layerClass 方法应该简单创建一个所需的Class 对象,并返回它。比如,一个支持OpenGL ES绘图的视图可能对该方法做以下实现:

+ (Class)layerClass

{
    return [CATiledLayer class];
}
           

--Each view calls its

layerClass

method early in its initialization process and uses the returned class to create its layer object. In addition, the view always assigns itself as the delegate of its layer object. At this point, the view owns its layer and the relationship between the view and layer must not change. You must also not assign the same view as the delegate of any other layer object. Changing the ownership or delegate relationships of the view will cause drawing problems and potential crashes in your application.

    每个视图在它的初始化过程早期调用它的layerClass方法,并使用layerClass返回的类来创建view的图层对象。 另外,视图总是作为它的层对象的代理。 在这时,视图拥有它的层,并且视图和图层之间的关系决不能改变。你也决不能让同一个视图成为任何其它图层对象的代理。改变视图的所属关系或代理关系将导致应用程序发生绘图问题以及潜在崩溃。

For more information about the different types of layer objects provided by Core Animation, see Core Animation Reference Collection.

     关于由内核动画提供的图层对象的不同类型的更多信息,请看Core Animation Reference Collection.

Embedding Layer Objects in a View -- 在视图中嵌入 图层对象

--If you prefer to work primarily with layer objects instead of views, you can incorporate custom layer objects into your view hierarchy as needed. A custom layer object is any instance of

CALayer

that is not owned by a view. You typically create custom layers programmatically and incorporate them using Core Animation routines. Custom layers do not receive events or participate in the responder chain but do draw themselves and respond to size changes in their parent view or layer according to the Core Animation rules.

     如果你更喜欢主要使用图层对象来代替视图工作,你可以根据需要在你的视图层次结构里纳入自定义图层对象。自定义图层对象是任何CALayer 的实例,它不属于任何视图。你通常通过程序创建自定义视图,并用内核动画程序纳入它们。自定义图层不接收事件或参与响应链,但是它们确实绘制它们自己并响应它们父视图或跟内核动画规则相关的层的尺寸改变。

Listing 3-2 shows an example of the

viewDidLoad

method from a view controller that creates a custom layer object and adds it to its root view. The layer is used to display a static image that is animated. Instead of adding the layer to the view itself, you add it to the view’s underlying layer.

     列表3-2 显示了一个例子,该例子是一个视图控制器中的viewDidLoad方法,它创建并添加一个自定义图层到它的根视图。该层用于显示一个被动画的静态图片。 不添加该层到视图本身,而是添加到视图下面的层上。

Listing 3-2  Adding a custom layer to a view

- (void)viewDidLoad {

    [super viewDidLoad];

    // Create the layer.

    CALayer* myLayer = [[CALayer alloc] init];

    // Set the contents of the layer to a fixed image. And set

    // the size of the layer to match the image size.

    UIImage layerContents = [[UIImage imageNamed:@"myImage"] retain];

    CGSize imageSize = layerContents.size;

    myLayer.bounds = CGRectMake(0, 0, imageSize.width, imageSize.height);

    myLayer = layerContents.CGImage;

    // Add the layer to the view.

    CALayer*    viewLayer = self.view.layer;

    [viewLayer addSublayer:myLayer];

    // Center the layer in the view.

    CGRect        viewBounds = backingView.bounds;

    myLayer.position = CGPointMake(CGRectGetMidX(viewBounds), CGRectGetMidY(viewBounds));

 

    // Release the layer, since it is retained by the view's layer

    [myLayer release];

}
           

--You can add any number of sublayers and arrange them into sublayer hierarchies, if you want. However, at some point, those layers must be attached to the layer object of a view.

        如果你需要,你可以添加任何数量的子图层并把它们整理到子图层的层次结构里。然而,在一些时候,那些图层必须被连接到一个视图的图层对象上。

--For information on how to work with layers directly, see Core Animation Programming Guide.

      关于如何跟层直接工作的信息,请看Core Animation Programming Guide.

Defining a Custom View -- 自定义视图

--If the standard system views do not do exactly what you need, you can define a custom view. Custom views give you total control over the appearance of your application’s content and how interactions with that content are handled.

       如果标准系统视图不能提供你所需要的,你可以定义一个自定义视图。自定义视图让你完全控制app的外观,以及处理客户跟视图内容的交互。

Note: If you are using OpenGL ES to do your drawing, you should use the

GLKView

class instead of subclassing

UIView

. For more information about how to draw using OpenGL ES, see OpenGL ES Programming Guide.

        注意:OpenGL ES技术不是使用UIView,而是使用

GLKView

类,看超链接

Checklist for Implementing a Custom View -- 实现自定义视图的清单

--The job of a custom view is to present content and manage interactions with that content. The successful implementation of a custom view involves more than just drawing and handling events, though. The following checklist includes the more important methods you can override (and behaviors you can provide) when implementing a custom view:

   一个自定义视图的工作是呈现内容并管理与该内容的交互。 但是,一个自定义视图的成功实现不仅仅涉及绘制和处理事件。以下清单包含了更多你实现一个自定义视图时可以重载的重要方法(以及你可以提供的行为):

  • Define the appropriate initialization methods for your view:

         为你的视图定义合适的初始化方法:

        • For views you plan to create programmatically, override the

initWithFrame:

method or define a custom initialization method.

            对于你打算以编程方式创建的视图,那就重写initWithFrame: 方法,或定义一个自定义初始化方法。

        • For views you plan to load from nib files, override the

initWithCoder:

method. Use this method to initialize your view and put it into a known state.

          对于你打算从nib文件载入的视图,那就重写initWithCoder: 方法。使用该方法来初始化你的视图并把它放入已知的状态。

  • Implement a

    dealloc

    method to handle the cleanup of any custom data.

          实现一个 

dealloc方法来处理任何自定义数据的清理工作。

  • To handle any custom drawing, override the

    drawRect:

    method and do your drawing there.

           要想处理任何自定义绘制,那就重写drawRect:方法,并在那完成绘图。

  • Set the

    autoresizingMask

    property of the view to define its autoresizing behavior.

         设置视图的autoresizingMask 属性来定义它的自动调整尺寸行为。

  • 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.

            在创建时为每个子视图设置的autoresizingMask 属性。

        • If your subviews require custom layout, override the

layoutSubviews

method and implement your layout code there.

            如果你的子视图要求自定义布局,重载 

layoutSubviews 方法并在这里实现你的布局代码。

  • To handle touch-based events, do the following:

          要想处理基于触摸的事件,那就完成以下事情: 

        • Attach any suitable gesture recognizers to the view by using the

addGestureRecognizer:

method.

           通过使用addGestureRecognizer: 方法来把合适的手势识别器连接到视图。

        • For situations where you want to process the touches yourself, override the

touchesBegan:withEvent:

,

touchesMoved:withEvent:

,

touchesEnded:withEvent:

, and

touchesCancelled:withEvent:

methods. (Remember that you should always override the

touchesCancelled:withEvent:

method, regardless of which other touch-related methods you override.)

        如果你想自己处理触摸事件,重写

touchesBegan:withEvent:

,

touchesMoved:withEvent:

touchesEnded:withEvent:

, 以及 

touchesCancelled:withEvent: 方法。无论你重载了哪些与触摸事件相关的方法,你都必须重写touchesCancelled:withEvent:

方法

  • If you want the printed version of your view to look different from the onscreen version, implement the

    drawRect:forViewPrintFormatter:

    method. For detailed information about how to support printing in your views, see Drawing and Printing Guide for iOS.

          如果你想让你的视图打印版本跟屏幕上的版本不同,实现drawRect:forViewPrintFormatter: 方法。 关于如何在视图里支持打印的详情,请看Drawing and Printing Guide for iOS.

--In addition to overriding methods, remember that there is a lot you can do with the view’s existing properties and methods. For example, the

contentMode

and

contentStretch

properties let you change the final rendered appearance of your view and might be preferable to redrawing the content yourself. In addition to the

UIView

class itself, there are many aspects of a view’s underlying

CALayer

object that you can configure directly or indirectly. You can even change the class of the layer object itself.

        除了使用子类来重写方法,有很多视图已经存在的属性和方法也可以完成很多事情。比如, 

contentMode

 和 

contentStretch 属性让你改变视图的最终渲染外形,并可能是你自己重新绘制内容更好。除了

UIView本身,视图的后台CALayer对象有很多方面你可以直接或间接配置。你甚至可以自己改变图层对象的类。

--For more information about the methods and properties of the view class, see UIView Class Reference.

     关于视图类的方法和属性的更多信息,请看UIView Class Reference.

Initializing Your Custom View -- 初始化自定义的视图

--Every new view object you define should include a custom

initWithFrame:

initializer method. This method is responsible for initializing the class at creation time and putting your view object into a known state. You use this method when creating instances of your view programmatically in your code.

      每一个你自定义的视图对象都应该包含一个自定义的initWithFrame: 初始化方法。该方法负责在创建时自定义该类并把视图对象放入一个已知的状态。当你在代码里通过程序创建视图的实例时,你将使用该方法。

--Listing 3-3 shows a skeletal implementation of a standard

initWithFrame:

method. This method calls the inherited implementation of the method first and then initializes the instance variables and state information of the class before returning the initialized object. Calling the inherited implementation is traditionally performed first so that if there is a problem, you can abort your own initialization code and return

nil

.

     列表 3-3 显示了一个标准initWithFrame:方法的框架实现。该方法首先调用该方法的被继承(super)实现,然后在返回初始化对象之前初始化实例变量和类的状态信息。调用被继承的实现通常都首先被执行,这样如果有问题,你可以退出你自己的初始化代码并返回nil。

Listing 3-3  Initializing a view subclass

- (id)initWithFrame:(CGRect)aRect {

    self = [super initWithFrame:aRect];

    if (self) {

          // setup the initial properties of the view

          ...

       }

    return self;

}
           

--If you plan to load instances of your custom view class from a nib file, you should be aware that in iOS, the nib-loading code does not use the

initWithFrame:

method to instantiate new view objects. Instead, it uses the

initWithCoder:

method that is part of the

NSCoding

protocol.

      如果你计划从一个nib文件载入你的自定义视图实例,你应该意识到在iOS里,nib载入的代码不适宜用initWithFrame:方法来实例化新的视图对象。作为替代,它使用

initWithCoder: 方法来初始化,该方法是NSCoding 方法的一部分。

--Even if your view adopts the

NSCoding

protocol, Interface Builder does not know about your view’s custom properties and therefore does not encode those properties into the nib file. As a result, your own

initWithCoder:

method should perform whatever initialization code it can to put the view into a known state. You can also implement the

awakeFromNib

method in your view class and use that method to perform additional initialization.

     即使你的视图采用了NSCoding协议,界面生成器也不会知道你的视图的自定义属性,因此没有把那些属性编码到nib文件。所以,你自己的initWithCoder: 方法,执行的是 “它能够把视图放入一个已知状态的”初始化代码。 你还可以在你的视图类里实现awakeFromNib 方法并使用该方法来执行额外的初始化。

Implementing Your Drawing Code                                              -- 实现绘图代码

--For views that need to do custom drawing, you need to override the

drawRect:

method and do your drawing there. Custom drawing is recommended only as a last resort. In general, if you can use other views to present your content, that is preferred.

     对于那些需要完成自定义绘制的视图,你需要重写

drawRect: 方法,并在那里书写你的绘制代码。自定义绘制建议只能作为最后的手段。 通常,如果你可以使用其它视图来呈现你的内容,那样做更好。

--The implementation of your

drawRect:

method should do exactly one thing: draw your content. This method is not the place to be updating your application’s data structures or performing any tasks not related to drawing. It should configure the drawing environment, draw your content, and exit as quickly as possible. And if your

drawRect:

method might be called frequently, you should do everything you can to optimize your drawing code and draw as little as possible each time the method is called.

       你的drawRect: 方法实现应该只做好一件事:绘制你的内容。该方法不是更新你的应用程序数据结构或执行任何跟绘制无关的任务。它应该配置绘图环境,绘制内容,以及尽可能快的退出来。并且如果你的drawRect:方法会经常被调用,你应该做你能做的一切来优化你的绘图代码,让它每次调用时尽可能少的绘图。

--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.

     当你调用视图的drawRect: 方法之前,UIKit为你的视图配置了基本的绘图环境。 特别是,它创建了一个图形上下文以及调整了坐标系统并裁减区域让其跟坐标系相匹配,让视图的边界可见。 因此,当drawRect: 方法被调用时,你可以使用本地绘图技术比如UIKit和Core Graphics开始绘制你的内容。你可以用UIGraphicsGetCurrentContext 函数获取一个指向当前图形上下文的指针。

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.

       重要提示:当前图形上下文只在调用视图的drawRect: 方法期间有效。 UIKit可能在每次调用此方法创建一个不同的图形上下文,因此你不应该尝试缓存该对象并在以后使用。

--Listing 3-4 shows a simple implementation of a

drawRect:

method that draws a 10-pixel-wide red border around the view. Because UIKit drawing operations use Core Graphics for their underlying implementations, you can mix drawing calls, as shown here, to get the results you expect.

     列表 3-4 显示了drawRect: 方法的一个简单实现, 它绘制了一个10个像素宽的红边框视图。 因为UIKit绘图操作使用内核图形(Core Graphics)来完成它们的后台实现, 你可以混合各种绘图调用,正如这里所示,来达到你期望的结果。

Listing 3-4  A drawing method

- (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGRect    myFrame = self.bounds;
 
    // Set the line width to 10 and inset the rectangle by

    // 5 pixels on all sides to compensate for the wider line.

    CGContextSetLineWidth(context, 10);

    CGRectInset(myFrame, 5, 5);

    [[UIColor redColor] set];

    UIRectFrame(myFrame);

}
           

--If you know that your view’s drawing code always covers the entire surface of the view with opaque content, you can improve system performance by setting the

opaque

property of your view to

YES

. When you mark a view as opaque, UIKit avoids drawing content that is located immediately behind your view. This not only reduces the amount of time spent drawing but also minimizes the work that must be done to composite your view with other content. However, you should set this property to

YES

only if you know your view’s content is completely opaque. If your view cannot guarantee that its contents are always opaque, you should set the property to

NO

.

      如果你知道你视图的绘图代码永远用不透明的内容覆盖整个视图表明,你就可以通过设置视图的 

opaque 属性为YES来提高系统的性能。当你把视图标记为不透明时,UIKit避免绘制那些因此在视图后面的内容。这样做不仅减少了绘图的总时间,还减少了视图必须跟别的内容的合成工作。然而,只要你知道你的视图内容是完全不透明的,那么你就应该设置该属性为YES。 如果你的视图不能保证都是不透明的,你应该设置它为NO。

--Another way to improve drawing performance, especially during scrolling, is to set the

clearsContextBeforeDrawing

property of your view to

NO

. When this property is set to

YES

, UIKIt automatically fills the area to be updated by your

drawRect:

method with transparent black before calling your method. Setting this property to

NO

eliminates the overhead for that fill operation but puts the burden on your application to fill the update rectangle passed to your

drawRect:

method with content.

       另一个提供绘图性能的方法,特别是滚动期间,是设置视图的clearsContextBeforeDrawing 属性为NO。 当这个属性被设置为YES, UIKit在调用你的drawRect: 方法之前自动用透明的黑色背景填充整个区域。设置该属性为NO消除了填充操作的开销(overhead),但是把负担加到应用程序填充更新矩形,并把内容传递给drawRect: 方法。

Responding to Events                                                -- 响应事件

--View objects are responder objects—instances of the

UIResponder

class—and are therefore capable of receiving touch events. When a touch event occurs, the window dispatches the corresponding event object to the view in which the touch occurred. If your view is not interested in an event, it can ignore it or pass it up the responder chain to be handled by a different object.

      视图对象都是响应者对象---都是UIResponder类的一个实例---因此能接收触摸事件。当一个触摸事件发生时,窗口发派相关的事件对象给触摸事件发生的视图。 如果你的视图对事件不感兴趣,view能忽视事件或者把事件传递到响应者链由别的对象来处理。

--In addition to handling touch events directly, views can also use gesture recognizers to detect taps, swipes, pinches, and other types of common touch-related gestures. Gesture recognizers do the hard work of tracking touch events and making sure that they follow the right criteria to qualify them as the target gesture. Instead of your application having to track touch events, you can create the gesture recognizer, assign an appropriate target object and action method to it, and install it on your view using the

addGestureRecognizer:

method. The gesture recognizer then calls your action method when the corresponding gesture occurs.

        除了直接处理触摸事件,视图还能使用手势识别器来侦察点击(taps), 滑动(swipes), 捏合(piches), 以及其他类型的常用触摸相关的手势。 手势触摸完成追踪触摸事件的困难工作,并确保它们遵守正确的标准来识别出它们的目标手势。 app不需要追踪触摸事件,你只需要创建手势识别器(gesture recognizer), 分配一个适当的目标对象和操作方法给手势识别器, 然后使用

addGestureRecognizer: 方法来把手势识别装载进你的视图,即可。当发生相应的手势时,便会自动执行该操作方法。

--If you prefer to handle touch events directly, you can implement the following methods for your view, which are described in more detail in Event Handling Guide for iOS:

如果你更喜欢直接处理触摸事件,你可以在视图里实现以下方法,它们在Event Handling Guide for iOS 里有着更详细的描述:

  • touchesBegan:withEvent:

  • touchesMoved:withEvent:

  • touchesEnded:withEvent:

  • touchesCancelled:withEvent:

--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

.

      视图的默认行为是一次只响应一个触摸事件。 如果用户按下第二个手指,系统忽视该触摸事件,并不向视图报告。 如果你计划从视图的事件处理器方法中追踪多手指手势,你需要设置视图的multipleTouchEnabled 属性来启动多触摸事件。

--Some views, such as labels and images, disable event handling altogether initially. You can control whether a view is able to receive touch events by changing the value of the view’s

userInteractionEnabled

property. You might temporarily set this property to

NO

to prevent the user from manipulating the contents of your view while a long operation is pending. To prevent events from reaching any of your views, you can also use the

beginIgnoringInteractionEvents

and

endIgnoringInteractionEvents

methods of the

UIApplication

object. These methods affect the delivery of events for the entire application, not just for a single view.

       一些视图,比如标签和图片,最初完全禁用事件处理。你可以通过改变视图的

userInteractionEnabled 属性值来控制视图是否允许接收触摸事件。当一个长事件操作待处理时,你可能临时设置该属性为NO来阻止用户操作视图的内容。为了阻止事件到达任何一个view,你还可以使用

UIApplication 对象的

beginIgnoringInteractionEvents

  和 

endIgnoringInteractionEvents 方法。 这些方法影响整个app事件的传递,不仅仅是影响单个视图。

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.

      注意:当动画在进行时,UIView 的动画方法通常不启动触摸事件。你可以通过适当地配置动画来重写该行为。 关于执行动画的更多信息,请看“Animations.”

--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.

      当view处理触摸事件时,UIKit 使用UIView 的 

hitTest:withEvent:

 和 

pointInside:withEvent: 方法来决定一个触摸事件是否发生在一个给定视图的边界内。 尽管很少需要重写这些方法,但你还是可以在你的自定义视图里重写它们来实现自定义触摸行为。 比如,你可以重载这些方法来阻止子视图处理触摸事件。

Cleaning Up After Your View                                           -- 清理视图所占的内存

If your view class allocates any memory, stores references to any custom objects, or holds resources that must be released when the view is released, you must implement a

dealloc

method. The system calls the

dealloc

method when your view’s retain count reaches zero and it is time to deallocate the view. Your implementation of this method should release any objects or resources held by the view and then call the inherited implementation, as shown in Listing 3-5. You should not use this method to perform any other types of tasks.

        如果你的视图类分配了任何内存,存储了指向任何自定义对象的引用,或保留了一些必须在视图被释放之后被释放的资源, 你必须实现一个dealloc 方法。系统在你的视图的保留计数值(retain count)变为0时调用dealloc方法,由该方法来释放视图。该方法的实现应该释放由视图保留的任何对象和资源,然后调用 继承于dealloc 方法 自身的实现,正如列表3-5所示。 你不应该使用该方法来执行任何其它类型的任务。

Listing 3-5  Implementing the

dealloc

method

- (void)dealloc {

    // Release a retained UIColor object

    [color release];

    // Call the inherited implementation

    [super dealloc];

}