0%

iOS中文文档:UIView

2015年,开始一个伟大的计划,翻译iOS文档。具体时间计划待定,先进行一两周。

UIView

继承自:UIResponder:NSObject
遵循:UITraitEnvironment, UIDynamicItem, NSObject, UICoordinateSpace, UIAppearanceContainer, UIAppearance, NSCoding 框架:iOS 2.0及以后版本的UIKit


UIView类在屏幕和界面上定义了一块矩形区域,用来管理那块区域的内容。在运行时,一个View对象处理它所在区域的内容渲染和交互。UIView类会使用背景颜色填充所在的矩形区域。更复杂的内容可以用UIView的子类来呈现,你自己来实现必要的绘画和事件处理代码。UIKit框架同时提供了一些标准子类,从简单的按钮到复杂的表格,你可以直接使用。如,UILabel对象画文本字符串,UIImageView对象画图像。

因为View对象是应用与用户交互的主要途径,他们有一系列的职责。以下列出一些:

  • 绘画和动画:
    • View在他们的矩形区域使用UIKit,Core Graphics和OpenGL ES之类的技术绘画
    • 一些视图属性可以动画到新的值
  • 布局和子View管理
    • 一个View可以包含0个或多个子View
    • 每个View都定义了相对父View大小改变的默认行为
    • 如有需要,一个View可以定义子View的大小和位置
  • 事件处理
    • View是一个响应者,可以处理UIResponder类定义的触摸和其他事件
    • View可以使用addGestureRecognizer方法安装手势识别器来处理常用手势

View可以内嵌到其他View,创建复杂的可视层级。这会在嵌入的View(子View)和被嵌入的View(父View)间创建父子关系。正常情况下,子View的可视区域不会被父View的边界剪辑,但在iOS里你可以使用clipsToBounds属性来修改这个行为。一个父View可能有多个子View,但一个子View只有一个父View,它负责确定子View的位置。

View的几何结构是通过它的框架(frame),边界(bounds)和中心(center)属性来定义的。frame定义了View相对父View坐标系的原点和大小,一般在View布局和调整尺寸或位置时使用。center属性可以在不改变view的大小来调整view的位置。bounds定义了view的内部尺寸,几乎只在自定义绘画代码时使用。frame的size部分和bounds矩形部分耦合在一起,所以可以使用两者中的一个或两个同时来改变view的大小。

更多关于如何使用UIView类,参见iOS View编程向导(待翻)

在iOS 2.x时,UIView的最大尺寸是1024*1024点,在iOS 3.0以后,不再强制限制大小,而是受限于内存消耗。让View尽可能小,无论运行在哪个版本的iOS上,都应该考虑避免View明显大于屏幕尺寸

创建一个View

用代码来创建View:
swift:

let viewRect = CGRect(x: 10, y: 10, width: 100, height: 100)
let myView = UIView(frame: viewRect)

Objective-c

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

这段代码创建了view,并把它放在父view坐标系的(10,10)点(一旦它被加到父view)。添加一个子view到另一个view上,用addSubview:方法。在iOS里,同级的view可以相互覆盖,而不会有任何问题,允许复杂的view布置。addSubview放置指定的view到它的同级view的顶部。你可以使用insertSubview:aboveSubview: 和 insertSubview:belowSubview: 方法指定子view的相对z坐标。你也可以使用exchangeSubviewAtIndex:withSubviewAtIndex: 方法交换已经添加的子view的位置。

View绘画周期

View绘画发生在需要时。当一个view第一次展示时,或者在布局变化时,它的整体或部分变得可见时,系统请求view绘出它的内容。对那些使用UIKit或Core Graphics包含自定义内容的view来说,系统会调用它的drawRect: 方法。你对该方法的实现,负责将view的内容画进当前的图形上下文(graphics context),系统自动优先调用该方法。这里创建了view内容的静态可视展现,接着会被展示在屏幕上。

当view的真实内容发生改变时,你有责任通知系统你的view需要重绘。通过调用view的setNeedsDisplay或setNeedsDisplayInRect:方法来通知。这些方法让系统知道它应该在下次绘画周期更新View.因为它一直等待直到下次绘画周期来更新View,你可以在多个view上调用这些方法,同时更新它们.

如果你用OpenGL ES来绘画,应该用GLKView类来代替UIView.更多信息关于如何用OpenGL ES绘画,参见 iOS OpenGL ES编程向导(待翻)

更多关于View绘画周期和你的view的角色,参见iOS View编程向导(待翻)

动画

改变多个View属性可以被动画展现,在一个短周期时间内,改变属性可以创建动画。UIView类做了很多执行动画的工作,但你仍然必须判断你需要哪些属性改变被动画。下面是两种不同的初始化动画方法:

  • 在iOS4.0及以后的版本中,使用基于块的动画方法(推荐)
  • 使用开始/提交(begin/commit)动画方法。

基于块的动画方法(像animateWithDuration:animations:)极大地简化了动画创建。只要调用一个方法,指定动画的参数,并且执行动画。然后,基于块的动画仅在iOS4及以后版本中可用。如果你的设备运行老版本的iOS,必须使用beginAnimations:context: 和 commitAnimations类方法标记动画开始和结束。

下面的属性是可以动画的:

  • @property frame

  • @property bounds

  • @property center

  • @property transform

  • @property alpha

  • @property backgroundColor

  • @property contentStretch

线程注意事项

操作用户界面必须发生在主线程。因此,你必须在应用主线程调用UIView类的方法。只有在创建view对象自身时可以不用严格遵守,但其他操作必须在主线程中。

子类化(继承)说明

对同样需要用户交互的可见内容来说,UIView类是一个关键的子类化点。尽管有很多好理由继承UIView,但我们只推荐在基本的UIView和系统自带的其他组件不能满足需要时继承UIView.继承UIView会在你实现的代码里消耗更多性能.(Apple写的代码比你的更好,有现成的就用现成的)。

避免子类化的更多信息, 见 ** 选择子类化 (待翻) **

覆盖方法

当子类化UIView时,只有少数的方法你必须覆盖,大多数方法你可以按需覆盖。因为UIView是一个高度可配的类,不用覆盖父类方法,同样有很多实现复杂的行为的途径,这些在 选择子类化 一节中介绍。你可以在你的UIView子类中考虑覆盖下面列表中的方法:

  • 初始化
    • initWithFrame 推荐覆盖。你同样可以实现自定义的初始化方法添加或代替此方法
    • initWithCoder: 如果你从一个Interface Builder的nib文件加载view,并且需要自定义初始化,覆盖该方法。
    • layerClass 仅当你的view需要用不同的Core Animation层后备保存时才要覆盖。例如,当你的view需要用平铺方式显示一块很大的可滚动区域时,你可能想要覆盖该方法返回CATiledLayer类.(不是很明白,原文: Implement this method only if you want your view to use a different Core Animation layer for its backing store. For example, if your view uses tiling to display a large scrollable area, you might want to override this method and return the CATiledLayer class.)
  • 绘画和打印
    • drawRect: 如果你的View画自定义的内容,就要实现该方法,否则避免覆盖该方法。
    • **drawRect:**forViewPrintFormatter: 仅当你需要在打印时,打印不同内容(与显示不同)才需要实现该方法。
  • 约束
    • requiresConstraintBasedLayout - 如果你的View类需要约束才能正常工作,实现该方法
    • updateConstraints 如果你的view需要在子view间创建约束,需要实现该方法
    • alignmentRectForFrame:, frameForAlignmentRect: - 实现这些方法覆盖你的view如何与其他view对齐
  • 布局
    • sizeThatFits: - 当你想在执行resize操作时有一个不同于默认的size,实现该方法。比如,你可以用这个方法阻止view收缩到子view不能正确显示的点
    • layoutSubviews - 如果你需要更精确控制子view,而不是使用限制或autoresizing行为,就需要实现该方法。
    • didAddSubview: , willRemoveSubview: 跟踪子view添加或删除事件
    • willMoveToSuperview:, didMoveToSuperview 跟踪当前view在view层次里的运动
    • willMoveToWindow:,didMoveToWindow 跟踪view(即将或已经)移动到另一个Window
  • 事件处理:
    • touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:, touchesCancelled:withEvent: 直接处理触摸事件(如果是手势,使用gesture recognizers)
    • **gestureRecognizerShouldBegin: ** 如果需要直接处理触摸事件,那么需要覆盖该方法,阻止手势识别器触发额外动作。

替代子类化

很多view行为可以配置而不用子类化。在你开始覆盖这些方法时,考虑是否可以修改下面的属性或行为来提供你需要的功能。 * addConstraint: - 为view和它的子view定义自动布局行为. * autoresizingMask - 当父view的frame改变时,提供自动布局行为。这些行为可以和约束(Constraint)合并 * contentMode -为view内容提供布局行为,与view的frame相反。这个属性同样影响内容应用view的缩放,是缓存还是重绘。 * contentStretch-定义view的部分可伸缩。这个行为通常用于实现按钮和其他复杂布局、可变尺寸、重绘代价高的view。 * hiddenalpha 改变view的不透明度或隐藏view * backgroundColor - 设置view的背景颜色 * Subviews 不在drawRect方法里绘制你的内容,使用嵌入图片或文本子view等方式 * Gesture recognizers - 使用手势识别器替代自己手工处理touch事件 * Animations - 使用内建动画支持代替自己写动画。Core Animation提供的动画支持很快很好用 * 基于图片的背景 - 对那些显示相对静态内容的view来说,考虑使用UIImageView对象加上手势识别替代子类化和自己绘制图片。同样,你也可以使用一般的UIView对象,分配你的图片作为view的CALayer对象内容。

动画是不需要子类化和实现复杂代码而让视觉改变的另一种方式。很多UIView的属性是可以动画的,意味着改变这些属性可以触发系统生成动画。启动动画只需要很少的一行代码指示那些改变需要被动画。更多view动画的信息,参考Animations

更多关于外观和行为配置的信息,见UIKit User Interface目录里的About Views

初始化View对象

-initWithFrame: 使用指定的frame矩形,初始化并且返回新的View对象。

声明:
SWIFT:

init(frame aRect: CGRect)

OBJECTIVE-C:

- (instancetype)initWithFrame:(CGRect)aRect

参数
aRect view的frame矩形,使用point测量。frame的原点是相对你将添加到的父view的。这个方法用frame矩形来设置中心点和边界。

返回值:
一个初始化的对象,如果不能创建,返回nil.

讨论
一个新的view对象必须插入到一个windows的view层级里才能使用。如果你用程序创建了一个view对象,这个方法是UIView类的指定初始器。子类可以覆盖这个方法来执行一些自定义的初始化,但必须在第一行调用super实现。
如果你用Interface Builder来设计你的界面,这个方法在从nib文件创建view对象时不会被调用。 nib里的对象使用**initWithCoder:**方法重建和初始化,它会修改view属性来匹配存储在nib文件里的属性。关于view如何从nib文件载入的详细信息,参见Resource Programming Guide.

导入声明
import UIKit

可用性
iOS 2.0及以后版本

配置View的可见外观

backgroundColor:View的背景颜色
声明
SWIFT:

@NSCopying var backgroundColor: UIColor?

OBJECTIVE-C

@property(nonatomic, copy) UIColor *backgroundColor

讨论: 改变这个属性可以动画,默认值是nil,表现为透明

导入声明
import UIKit

可用性
iOS 2.0及以后版本

参见

  • alpha
  • opaque

hidden一个判断view是否隐藏的boolean值

声明
SWIFT:

var hidden: Bool

OBJECTIVE-C

@property(nonatomic, getter=isHidden) BOOL hidden

讨论: 设置这个值为YES隐藏view,NO显示View,默认是NO

一个隐藏的view从窗口消失并且不接收输入事件。然而,它还留在它的父view的子view列表中,并且跟往常一样参与autoresizing。隐藏一个带有子view的view,跟隐藏这些子view(包括他们的子view)有一样的效果。这个效果是含蓄的并且不会修改子view的hidden属性.
如果隐藏的view是窗口的当前第一响应者,会导致下一个view成为第一响应者(得到焦点,是这个意思么?)

导入声明
import UIKit

可用性
iOS 2.0及以后版本

alpha View的不透明度

声明
SWIFT:

var alpha: CGFloat

OBJECTIVE-C

@property(nonatomic) CGFloat alpha

讨论: 这个属性的值是一个浮点值,范围从0.0到1.0,0.0代表完全透明,1.0代表完全不透明。这个值只能当前view有效,不影响内嵌的子view
改变这个属性可以动画

导入声明
import UIKit

可用性
iOS 2.0及以后版本

参见

  • backgroundColor
  • opaque

未完待续