iOS UIView非常用方法及属性详解
在调用视图的drawRect:方法之前,UIKit 会自动对描画环境进行配置,使左上角成为
坐标系统的原点,在这个环境中发生的Quartz 调用都可以正确地在视图中描画。
视图对象通过frame、bounds、和center 属 性声明来跟踪自己的大小和位置。frame 属性包含一个矩形,即边框矩形,用于指定视图相对于其父视图坐标系统的位置和大小。bounds 属性也包含一个矩形,即边界矩形,负责定义视图相对于本地坐标系统的位置和大小。虽然边界矩形的原点通常被设置为(0, 0),但这并不是必须的。center 属性包含边框矩形的中心点。
当您在代码中通过initWithFrame:方法创建一个视图对象时,其frame 属性就会被设置。该方法同时也将bounds 矩形的原点初始化为(0.0, 0.0),大小则和视图的边框相同。然后center 属性会被设置为边框的中心点。
缺省情况下,视图的边框并不会被父视图的边框裁剪。如果您希望让一个视图裁剪
其子视图,需要将其clipsToBounds 属性设置为YES。
举例来说,UIView 类中包含一个transform 属性声明,您可以通过它来对整个视图实行各种类型的平移、比例缩放、和变焦缩放效果。缺省情况下,这个属性的值是一个恒等变换,不会改变视图的外观。在加入变换之前,首先要得到该属性中存储的CGAffineTransform 结构,用相应的Core Graphics 函数实行变换,然后再将修改后的变换结构重新赋值给视图的transform 属性。
视图的contentMode 属性决定了边界变化和缩放操作作用到视图上产生的效果。
缺省情况下,这个属性的值被设置为UIViewContentModeScaleToFill,意味着视图内容总是被缩放,以适应新的边框尺寸。
不同的UIViewContentMode 常量(比如UIViewContentModeTop 和
UIViewContentModeBottomRight)可以使当前的内容在视图的不同角落或沿着视图的不同边界显示,还有一种模式可以将内容显示在视图的中心。
当您希望在应用程序中实现尺寸可调整的控件时,请务必考虑使用内容模式。
内容模式通常有助于避免视图内容的描画,但是当您希望对缩放和尺寸调整过程中的视图外观进行特别的控制时,也可以使用UIViewContentModeRedraw 模式
如果视图的autoresizesSubviews 属性声明被设置为YES,则其子视图会根据
autoresizingMask 属性的值自动进行尺寸调整。否则,应用程序就必须通过重载layoutSubviews 方法来提供自己的实现。
如果要使一个视图和其父视图左下角的相对位置保持不变, 可以加入UIViewAutoresizingFlexibleRightMargin和
UIViewAutoresizingFlexibleTopMargin 常量,并将结果赋值给autoresizingMask 属性。当同一个轴向有多个部分被设置为可变时,尺寸调整的裕量会被平均分配到各个部分上。
UIViewAutoresizingNone 这个常量如果被设置,视图将不进行自动尺寸调整。
UIViewAutoresizingFlexibleHeight
这个常量如果被设置,视图的高度将和父视图的高度一起成比
例变化。否则,视图的高度将保持不变。
UIViewAutoresizingFlexibleWidth
这个常量如果被设置,视图的宽度将和父视图的宽度一起成比
例变化。否则,视图的宽度将保持不变。
UIViewAutoresizingFlexibleLeftMargin
这个常量如果被设置,视图的左边界将随着父视图宽度的变化
而按比例进行调整。否则,视图和其父视图的左边界的相对位
置将保持不变。
UIViewAutoresizingFlexibleRightMargin
这个常量如果被设置,视图的右边界将随着父视图宽度的变化
而按比例进行调整。否则,视图和其父视图的右边界的相对位
置将保持不变。
UIViewAutoresizingFlexibleBottomMargin
这个常量如果被设置,视图的底边界将随着父视图高度的变化
而按比例进行调整。否则,视图和其父视图的底边界的相对位
置将保持不变。
UIViewAutoresizingFlexibleTopMargin
这个常量如果被设置,视图的上边界将随着父视图高度的变化
而按比例进行调整。否则,视图和其父视图的上边界的相对位
置将保持不变。
如果您通过Interface Builder 配置视图,则可以用Size 查看器的Autosizing 控 制来设置每个视图的自动尺寸调整行为。上图中的灵活宽度及高度常量和Interface Builder 中位于同样位置的弹簧具有同样的行为,但是空白常量的行为则是正好相反。换句话说,如果要将灵活右空白的自动尺寸调整行为应用到Interface Builder 的某个视图,必须使相应方向空间的Autosizing 控制为空,而不是放置一个支柱。
如果视图的autoresizesSubviews 属性被设置为NO,则该视图的直接子视图的所有自动尺寸调整行为将被忽略。类似地, 如果一个子视图的自动尺寸调整掩码被设置为
UIViewAutoresizingNone,则该子视图的尺寸将不会被调整,因而其直接子视图的尺寸也不会被调整。
视图层次中的父-子关系可以帮助我们定义应用程序中负责处理触摸事件的对象链
创建一个新的视图对象时,需要为其分配内存,并向该对象发送一个initWithFrame:消息,以对其进行初始化。举例来说,如果您要创建一个新的UIView 类的实例作为其它视图的容器,则可以使用下面的代码:
CGRect viewRect = CGRectMake(0, 0, 100, 100);
UIView* myView = [[UIView alloc] initWithFrame:viewRect];
在iPhone 程序中,有两个地方最常用于创建视图和子视图, 它们是应用程序委托对象的applicationDidFinishLaunching:方法和视图控制器的loadView 方法。
调用父视图的addSubview:方法来添加视图,该方法将一个视图添加到子视图列表的最后。
调用父视图的insertSubview:...方法可以在父视图的子视图列表中间插入视图。
调用父视图的bringSubviewToFront: 、sendSubviewToBack: 、或
exchangeSubviewAtIndex:withSubviewAtIndex:方法可以对父视图的子视图进行重新排序。使用这些方法比从父视图中移除子视图并再次插入要快一些。
调用子视图(而不是父视图)的removeFromSuperview 方法可以将子视图从父视图中移除。
创建一个带有视图的窗口
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the window object and assign it to the
// window instance variable of the application delegate.
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
window.backgroundColor = [UIColor whiteColor];
// Create a simple red square
CGRect redFrame = CGRectMake(10, 10, 100, 100);
UIView *redView = [[UIView alloc] initWithFrame:redFrame];
redView.backgroundColor = [UIColor redColor];
// Create a simple blue square
CGRect blueFrame = CGRectMake(10, 150, 100, 100);
UIView *blueView = [[UIView alloc] initWithFrame:blueFrame];
blueView.backgroundColor = [UIColor blueColor];
// Add the square views to the window
[window addSubview:redView];
[window addSubview:blueView];
// Once added to the window, release the views to avoid the
// extra retain count on each of them.
[redView release];
[blueView release];
// Show the window.
[window makeKeyAndVisible];
}
当您为某个视图添加子视图时,UIKit 会向相应的父子视图发送几个消息,通知它们当前发生的状态变化。您可以在自己的定制视图中对诸如willMoveToSuperview: 、
willMoveToWindow: 、willRemoveSubview: 、didAddSubview: 、didMoveToSuperview 、和didMoveToWindow这样的方法进行重载,以便在事件发生的前后进行必要的处理,并根据发生的变化更新视图的状态信息。
在视图层次建立之后,您可以通过视图的superview 属性来取得其父视图,或者通过subviews属性取得视图的子视图。您也可以通过isDescendantOfView:方法来判定一个视图是否在其父视图的视图层中。一个视图层次的根视图没有父视图,因此其superview 属性被设置为nil。对于当前被显示在屏幕上的视图,窗口对象通常是整个视图层次的根视图。
UIView 类定义了下面这些方法,用于在不同的视图本地坐标系统之间进行坐标转换:
convertPoint:fromView:
convertRect:fromView:
convertPoint:toView:
convertRect:toView:
UIWindow 的版本则使用窗口坐标系统。
convertPoint:fromWindow:
convertRect:fromWindow:
convertPoint:toWindow:
convertRect:toWindow:
UIView 类中包含一个tag 属性。借助这个属性,您可以通过一个整数值来标识一个视图对象。您可以通过这个属性来唯一标识视图层次中的视图,以及在运行时进行视图的检索(基于tag 标识的检索比您自行遍历视图层次要快)。tag 属性的缺省值为0。您可以通过UIView 的viewWithTag:方法来检索标识过的视图
动画块从调用UIView 的beginAnimations:context:类方法开始,而以调用commitAnimations类 方法作为结束。在这两个调用之间,您可以配置动画的参数和改变希望实行动画的属性值。一旦调用commitAnimations 方法,UIKit 就会开始执行动画,即把给定属性从当前值到新值的变化过程用动画表现出来。动画块可以被嵌套,但是在最外层的动画块提交之前,被嵌套的动画不会被执行。
frame 视图的边框矩形,位于父视图的坐标系中。
bounds 视图的边界矩形,位于视图的坐标系中。
center 边框的中心,位于父视图的坐标系中。
transform 视图上的转换矩阵,相对于视图边界的中心。
alpha 视图的alpha 值,用于确定视图的透明度。
用setAnimationStartDate:方法来设置动画在commitAnimations 方法返回之后的发生日期。缺省行为是使动画立即在动画线程中执行。
用setAnimationDelay:方法来设置实际发生动画和commitAnimations 方法返回的时间点之间的间隔。
用setAnimationDuration:方法来设置动画持续的秒数。
用setAnimationCurve:方法来设置动画过程的相对速度,比如动画可能在启示阶段逐渐加速,而在结束阶段逐渐减速,或者整个过程都保持相同的速度。
用setAnimationRepeatCount:方法来设置动画的重复次数。
用setAnimationRepeatAutoreverses:方法来指定动画在到达目标值时是否自动反向播放。您可以结合使用这个方法和setAnimationRepeatCount:方法,使各个属性在初始值和目标值之间平滑切换一段时间。
您可以通过UIView 的
setAnimationDelegate: 类方法来设置委托, 并通过setAnimationWillStartSelector: 和
setAnimationDidStopSelector:方法来指定接收消息的选择器方法。消息处理方法的形式如下:
- (void)animationWillStart:(NSString *)animationID context:(void *)context;
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void
*)context;
上面两个方法的animationID 和context 参数和动画块开始时传beginAnimations:context:方法的参数相同:
animationID - 应用程序提供的字符串,用于标识一个动画块中的动画。
context - 也是应用程序提供的对象,用于向委托对象传递额外的信息。
setAnimationDidStopSelector:选择器方法还有一个参数—即一个布尔值。如果动画顺利完成,没有被其它动画取消或停止,则该值为YES。
任何时候,当视图的布局发生改变时,UIKit 会激活每个视图的自动尺寸调整行为,然后调用各自的layoutSubviews 方法,使您有机会进一步调整子视图的几何尺寸。
您的应用程序调用视图的setNeedsLayout 或layoutIfNeeded 方法来强制进行布局。
您的应用程序调用视图背后的层对象的setNeedsLayout 方法来强制进行布局。
您也可以用layoutSubviews 方法来调整作为子层链接到视图层的定制CALayer 对
象
有些时候,应用程序数据模型的变化会影响到相应的用户界面。为了反映这些变化,您可以将相应的视图标识为需要刷新(通过调用setNeedsDisplay 或setNeedsDisplayInRect:方法)
您可以通过改变视图的hidden 属性声明来隐藏或显示视图
初始化一个视图的子类
- (id)initWithFrame:(CGRect)aRect {
self = [super initWithFrame:aRect];
if (self) {
// setup the initial properties of
the view
...
}
return self;
}
在iPhone OS 中,装载nib 的代
码并不通过initWithFrame:方法来实例化新的视图对象,而是通过NSCoding 协议定义的initWithCoder:方法来进行。
drawRect:方法的一个简单实现,即在视图边界描画一个10像素宽的红色
边界。由于UIKit 描画操作的实现也是基于Quartz,所以您可以像下面这样混合使用不同的描画调用来得到期望的结果。
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect myFrame = self.bounds;
CGContextSetLineWidth(context, 10);
[[UIColor redColor] set];
UIRectFrame(myFrame); //捣鼓来捣鼓去,搞得复杂!!!
}
处理触摸事件的视图通常需要实现下面的所有方法
touchesBegan:withEvent:
touchesMoved:withEvent:
touchesEnded:withEvent:
touchesCancelled:withEvent:
激活多点触摸事件:multipleTouchEnabled 属性声明设置为YES。
您可以通过改变视图的userInteractionEnabled 属性值来控制视图是否可以对事件进行处理。
还可以使用UIApplication 对象的beginIgnoringInteractionEvents 和
endIgnoringInteractionEvents 方法
UIKit 会通过UIView 的hitTest:withEvent:和pointInside:withEvent:方法
来确定触摸事件是否发生在指定的视图上。