UIViewContentModeScaleToFill, UIViewContentModeScaleAspectFit, 和 UIViewContentModeScaleAspectFill时,contentStretch参数才起作用。
注意:contentStretch参数在ios6系统之后已经不被推荐使用。可以使用UIImage的resizableImageWithCapInsets方法来完成填充背景的工作。
Frame,Bounds和Center的关系。
Frame和center主要用来生成当前视图的形状。比如,你用这些参数来构建视图链或者改变视图的位置和大小(在运行时)。如果只是改变视图的位置(而没有大小),推荐使用center参数。center的值在大部分时候有效,即使改变了视图的大小和方向;但这些情况下frame会变。
clipsToBounds默认为NO。也就是说,当子视图的区域超过父视图的区域时,仍然可以显示超出父视图的区域。我们可以把clipsToBounds设置为YES来避免这种情况。但是,不管clipsToBounds设置为yes或no,在父视图意外区域的点击事件都不会被传导给父视图或子视图。
坐标系统转换
注意:当修改视图的transform参数,所有执行的操作都是与视图的center point相关联的。
/* Return a transform which translates by `(tx, ty)':
t' = [ 1 0 0 1 tx ty ]
其实tx,ty就是视图在x,y轴的位移。
*/
CG_EXTERN CGAffineTransform CGAffineTransformMakeTranslation(CGFloat tx,
CGFloat ty) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Return a transform which scales by `(sx, sy)':
t' = [ sx 0 0 sy 0 0 ]
其实,sx,sy就是视图在x,y轴的scale
*/
CG_EXTERN CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Return a transform which rotates by `angle' radians:
t' = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ]
其实,angle就是视图旋转的角度*/
CG_EXTERN CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Translate `t' by `(tx, ty)' and return the result:
t' = [ 1 0 0 1 tx ty ] * t */
CG_EXTERN CGAffineTransform CGAffineTransformTranslate(CGAffineTransform t,
CGFloat tx, CGFloat ty) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Scale `t' by `(sx, sy)' and return the result:
t' = [ sx 0 0 sy 0 0 ] * t */
CG_EXTERN CGAffineTransform CGAffineTransformScale(CGAffineTransform t,
CGFloat sx, CGFloat sy) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Rotate `t' by `angle' radians and return the result:
t' = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] * t */
CG_EXTERN CGAffineTransform CGAffineTransformRotate(CGAffineTransform t,
CGFloat angle) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Invert `t' and return the result. If `t' has zero determinant, then `t'
is returned unchanged. */
CG_EXTERN CGAffineTransform CGAffineTransformInvert(CGAffineTransform t)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
/* Concatenate `t2' to `t1' and return the result:
t' = t1 * t2 */
CG_EXTERN CGAffineTransform CGAffineTransformConcat(CGAffineTransform t1,
CGAffineTransform t2) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
注意:如果视图的变换属性不是恒等变换,那么视图的frame属性是未定义的并且要被忽视掉。当对视图应用变换,我们必须用视图的bounds和center属性来获取视图的位置和大小。视图内的子视图的frame仍然是有效的,因为他们是和父视图的bounds相关的。
运行时交互模型
运行时交互模型
顺序:
1.用户触摸屏幕
2.硬件传导触摸事件给UIKit框架
3.UIKit框架打包触摸事件为一个UIEvent对象,并传导给正确的视图。(事件传导机制)
4.你的事件处理代码响应这个时间。比如
1)改变视图或者子视图的参数
2)调用setNeedsLayout方法来使视图变成需要布局更新
3)调用setNeedsDisplay或者setNeedsDisplayInRect:方法来使视图标记为需要重绘
4)通知一个控制器,来使某些数据做更新
当然,这些响应代码都是根据自己的业务来的。
5.如果视图的形状改变了,那么子视图也会跟着改变,并遵循如下规则:
1)如果配置子视图为autoresizing的,那么UIKit会根据配置规则调整子视图
2)如果视图执行layoutSubviews方法,UIKit调用这个方法。
你可以重载layoutSubviews方法,来改变子视图的位置和大小。比如,一个大的滑动区域需要很多子视图, 但是把所有子视图都放在内存中不合适。因此,在执行方法时,视图可以隐藏不在当前屏幕内的子视图或者 重新布置子视图的位置并在新的位置内填入正确的内容。作为这次处理的一部分,视图的布局代码也可以标 记子视图为需要重绘。
6.如果视图标记为需要重绘,UIKit会给视图发送重绘命令。
7.所有的更新会混合视图可视内容的其他部分,并一起发送给绘图硬件来显示。
8.视图硬件传输渲染内容到屏幕上。
注意:之前的这些步骤主要用的是标准系统视图和绘图技术。应用OpenGLES来绘图的应用一般配置一个全屏幕的视图并结合OpenGLES绘图上下文直接绘图。这种情况下,视图仍然可以响应触摸事件,但是,因为是全屏幕视图,视图不需要重新布局子视图。
在滚动的时候调整你的绘图行为
滚动可以在短时间内产生大量的视图更新。如果您的视图的绘制代码没有适当调整,为您的视图滚动的表现可能是缓慢的。而不是试图以确保您的视图的内容是原始的在任何时候,请考虑在滚动操作开始时更改您的视图的行为。例如,滚动正在进行中,你可以暂时降低你呈现的内容的质量或改变内容模式。当滚动停止,然后你可以回到你的观点到以前的状态,并根据需要更新的内容。
不要给自定义Controls添加子视图
尽管技术上可以给Control的子类add子视图,但是不建议这样做。比如给UIButton控件增加一个图片,这种行为会在不知道什么时候导致错误。