UIView在屏幕上定义了长方形的区域,并定义了在该区域中内容的管理接口。在运行时,一个view对象能够处理在它区域内的内容以及用户交互事件。值得注意的是,控制程序的应用界面必须在主线程中完成。因此,必须在应用的主线程中调用UIView类的方法。
UIViewd的主要职责:
- 绘图与动画
- 布局和子视图管理
- 事件处理
绘画周期
当view首次出现,或者当layout发生改变而引起的全部or部分试图的内容出现时,系统会让view来绘制内容。若view包含使用UIKit或者Core Graphics的自定义内容时,会调用view的drawRect:方法。
当试图的实际内容发生改变时,coder有责任通知系统重新绘制内容。可以通过调用方法:① setNeedsDisplay;② setNeedsDisplayInRect: 来完成。这些方法会让系统在下一个绘制周期进行试图的更新。由于它将会等到下个绘制周期才更新视图,因此可以在多个view上调用这些方法,使得它们同时更新。
常用属性
- @property (nonatomic, getter=isOpaque) BOOL opaque
- 决定view是否为不透明的。这个属性提示绘画系统如何对待view,若设置为YES:绘画系统认为view是完全不透明的,如此可以优化一些绘画操作以及提高性能;若设置为NO:绘画系统将view与其他内容复合。该值默认为YES。当该值为YES时,alpha属性的设置结果是不可控的,若希望view透明,则应该将该值设置为NO。
- @property (nonatomic) BOOL clipsToBounds
- 该属性决定当前view的bounds是否限制它的子视图。设置为YES:导致子视图会根据receiver的bounds而修剪;设置为NO:子视图超出receiver bounds的可见部分不会被修剪,默认为NO。
- @property (nonatomic) UIViewContentMode contentMode
- 当bounds发生改变时,该属性决定了views如何展示它的内容。
- @property (nonatomic) CGFloat contentScaleFactor
- view的比例尺因子,决定了当view的内容从逻辑坐标空间到设备坐标空间映射。通常设置为1.0或2.0, 值越大,表示每个点在view中表示更多的像素。例如:如果比例尺因子为2.0,则若frame的大小为100*100,则实际展示内容的像素大小为:200 * 200。
- @property (nonatomic, getter = isExclusiveTouch) BOOL exclusiveTouch
- 该属性决定view是否独占处理触摸事件。当属性设置为YES时会阻塞在相同window中其他view的触摸事件,默认设置为NO。
- @property (nonatomic) NSInteger tag
- 在应用中唯一标示该view对象
- @property (nonatomic, readonly, retain) CALayer *layer
- view的核心动画层,用于绘画。
- @property (copy, nonatomic) NSArray *motionEffects
- view的动画效果数组
- @property (nonatomic, getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled
- 是否允许多点触控
- @property (nonatomic, readonly, copy) NSArray *subviews
- view的直接子视图数组
- @property (nonatomic, readonly) UIView *superView
- view的父视图
- @property (nonatomic, getter == isUserInteractionEnabled) BOOL userInteractionEnabled
- 决定是否忽略用户事件,是否将事件从事件队列中移除。但设置为NO时:用户事件(例如:触摸或者键盘)将会被忽略,并从事件队列中移除。设置为YES:事件将会正常的传递到view。
- @property (nonatomic, retain) UIColor *tintColor
- 在视图层次中第一个非默认的色彩颜色值。如果系统在层次中无法找到非默认的颜色,该属性将会替换系统定义的颜色。
- 如果view的tintAdjustmentMode设置为UIViewTintAdjustmentModeDimed,则tintColor的默认值会自动变得模糊。
常用方法
子类化重写方法
在对UIView子类化时,只有一些方法重写才有意义。由于UIView是一个高度可配置的类,因此除了override之外,有许多其他的方式实现复杂的视图行为。
初始化
- initWithFrame:
- 实现该方法能够实现自定义初始化的操作
- initWithCoder:
- 如果此刻从nib文件中载入视图,并需要自定义初始化操作时可以实现该方法
- layerClass:
- 当希望view是哟高另外的核心动画层时可以重写该方法。例如:如果view使用tiling显示可滑动的大面积区域,可以重写该方法来返回CATiledLayer类。
绘画与打印
- drawRect:
- 如果要绘制自定义内容,则需要实现该方法。
- drawRect:forViewPrintFormatter:
- 只有需要在打印过程中绘制不同的视图内容时才需要实现该方法。
限制
- requiresConstraintBasedLayout
- 如果希望view的constraints正常工作,则需要实现该方法。
- updateConstrains
- 如果需要在子类之间创建自定义的constraints则需要实现该方法。
- aligmentRectForFrame, frameForAlignmentRect
- 实现上述两个方法能够定义当前的view与其他view的对齐方式。
布局
- sizeThatFits
- 如果希望view相较于正常调整大小操作而言有不同的默认大小时,可以实现该方法。例如:可以通过实现该方法避免当view缩小时子视图无法正常显示的问题。
- layoutSubviews
- 除了constraint和提供的自动调节大小之外,如果需要对子视图的布局更精准的控制,可以实现该方法。
- didAddSubview:,willRemoveSubview:
- 通过实现上述方法,能够追踪子视图的添加和移除操作
- willMoveToSuperView:,didMoveToSuperview
- 通过实现上述方法,能够追踪当前view在试图层次中的动作。
- 通过实现上述方法,能够追踪当前view在试图层次中的动作。
- willMoveToWindow:, didMoveToWindow
- 通过实现上述方法,能够追踪当前view在另一个window中的动作。
- 通过实现上述方法,能够追踪当前view在另一个window中的动作。
事件处理
- touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:, touchesCancelled:withEvent:
- 通过实现上述方法,能够直接处理触摸事件。(对于手势输入,使用gesture recognizers)
- 通过实现上述方法,能够直接处理触摸事件。(对于手势输入,使用gesture recognizers)
- gestureRecongizerShouldBegin:
- 通过实现上述方法,能够使view直接处理触摸事件,并且能够避免触发额外动作时的附加gesture recognizers。
- 通过实现上述方法,能够使view直接处理触摸事件,并且能够避免触发额外动作时的附加gesture recognizers。
其他
- addConstrains:
- 定义view和它的子视图的自动布局行为
- autoresizingMask
- 当父视图的frame改变时,提供自动布局行为。这些行为可以与constraints相结合。
- contentMode
- 为view的内容提供与view的frame相对的布局行为。该属性会影响view的内容大小如何适应view,是否缓存或重新绘制
- contentStretch
- 定义view可伸展的部分。该行为主要用于实现拥有复杂布局的按钮和自他可变大小视图,其中每次的重绘制会影响性能
其他方法
子视图
- -(void)addSubview:(UIView *)view
- 在view的子视图列表之后加入一个新的子视图(追加)。
- -(void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview
- 在视图层次中指定的siblingSubview之上插入一个视图。
- -(void)insertSubview:(UIVIew *)view atIndex:(NSInteger)index
- 在指定位置插入视图,index不能超过view中包含的子视图的个数。
- -(void)insertSubview:(UIVIew *)view belowSubview:(UIView *)siblingSubview
- 在视图层次中指定siblingSubview之下插入一个视图。
- -(void)sendSubviewToBack:(UIView *)view
- 将指定的子视图view移动到所有sibling视图的后面。例如:我们希望增加一个全屏的按钮button,单击时能够取消键盘。如果按添加的顺序,此时button在最前面,被覆盖在其下的field无法响应触控事件,调用该函数之后,button将移动到field之后,如此单击空白处时会触发button的事件。
- -(void)bringSubViewToFront:(UIView *)view
- 将指定的子视图移动到所有sibling视图的前面,与sendSubViewToBack:相反。
- -(UIView *)viewWithTag:(NSInteger)tag
- 获得当前view的层次结构中与tag相匹配的视图。该函数会搜索当前的view以及所有它的子视图。
- -(void)exchangeSubViewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2
- 交换子视图在view子视图列表中的位置
【注】一个子视图只能有一个superView,如果插入的子视图已经有superView了,会移除原有的superView,将superView替换成新插入到的view。
事件
- -(BOOL)endEditing:(BOOL)fore
- 导致视图和它嵌入的text fields取消first responder状态。fore为YES时:强制取消first responder状态;NO,非强制。返回值为YES:表明view成功取消first responder状态;NO:未成功。
- -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
- 返回在receiver视图层次中的最远后代中包含指定point子视图。该方法通过pointInside:withEvent:方法遍历视图层次中每一个子视图,从而决定哪个子视图应该接受触摸事件。如果pointInside:withEvent返回YES,则继续遍历子视图的层次结构找到包含指定point的最远子视图。如果view不包含point,则这个视图层次分支将会被忽略。
- 该方法很少直接调用,一般会重写该方法来隐藏子视图的触摸事件。
- -(void)tintColorDidChange
- 当tintColor属性改变时会触发该方法的调用。
布局
- -(CGSize)sizeThatFits:(CGSize) size
- 计算适合子视图的最佳视图大小。
- -(void)sizeToFits
- 重新调整大小和移动receiver视图使其包含它的子视图
- -(CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize
- 返回满足constrants的视图大小。其中targetSize表示你是否希望符合限制的最小or最大大小。
限制(Constraints)
- -(void)addConstraint:(NSLayoutConstraint *)constraint
- 在receiving视图或者它的子视图布局中添加一个限制
- -(void)addConstraints:(NSArray *)constraints
- 在receiving视图或者它的子视图布局中添加多个限制
- -(BOOL)needsUpdateConstraints
- 检查视图的限制是否需要更新
- -(void)removeConstraint:(NSLayoutConstraint *)constraint
- 移除一个指定的限制
- -(void)removeConstraints:(NSArray *)constraints
- 移除多个指定的限制
- -(void)updateConstraints
- 如果自定义视图发现视图的某一个限制非法,需要立即移除这个限制,然后会调用setNeedsUpdateConstrains来通知constraints需要更新。在更新布局前,updateConstraints会被触发,允许当自定义视图的属性没有改变时验证view内容所有的限制
- 【注】在实现最后一个一定要调用方法:[super updateConstraints]
- -(void)updateConstraintsIfNeeded
- 更新revceiving视图和子视图的限制。无论何止一个视图触发了一个新的布局,系统会调用这个方法来保证视图的constraints和它的子视图都从当前视图层次和它的constraints更新了信息。该方法由系统自动条用,也可以手动调用来检查最新的constraints。该方法不能被重写!
动画
属性
UIView完成了大部分的动画操作,但是仍然需要设置一些属性来自定义动画:
- @property (nonatomic) frame
- frame矩形,标书view在其父视图的坐标系统中的位置和大小。设置该属性会相应的改变center和bounds属性。
- @property (nonatomic) CGRect bounds
- 描述view在本身的协同系统中的位置和大小。bounds矩形代表了与view的frame矩形相同的可见部分,bounds的默认矩形设置为(0,0),通过改变bounds的值能够选择显示view的不同部分。bounds矩形的大小与frame矩形相耦合,因此改变任意一个会影响另一个。bounds大小的改变会相对于它的中心点放大或缩小。
- 改变frame矩形会自动重新显示receiver,而不会触发drawRect:。如果希望在frame矩形改变时触发drawRect:,则需要将contentMode属性设置为UIViewContentModeRedraw。
- @property (nonatomic) center
- 该属性表示frame的中心点。center属性指定了它的父视图的坐标系统,设置该属性会改变frame属性。
- 该属性的改变可以动画,使用beginAnimations:context:方法开始,通过commitAnimations方法结束动画。
- @property (nonatomic) transform
- 相对于bounds的center,指定应用到receiver的变形。transform的原始值为center属性的值,或者如果发生改变了则为layer的anchorPoint属性。
- 该属性的改变可以动画,使用beginAnimations:context:方法开始,通过commitAnimations方法结束动画。
- @property (nonatomic) CGFloat alpha
- 透明度,取值范围:[0.0, 1.0]。值越接近1.0,透明度越低。
- @property (nonatomic, copy) backgroupColor
- 背景颜色。该值可以通过动画设置,默认值为nil,即透明背景颜色。
方法
- -(void)beginAnimations:(NSString *)animationId context:(void *)context
- 标识动画块的起始位置,该方法会通知系统需要执行一个或多个特定的动画。其中,animationId是应用中动画的标识符,context中包含了与动画相关的自定义数据。
- -(void)commitAnimations
- 标识动画的提交位置,如果当前的动画集是离中心最远的集,则该方法会在应有返回到运行循环时启动动画。如果当前动画集嵌套在另一个动画集中,该方法会等待直到外层动画集的动画提交,然后在某一点一起提交所有动画。
- +(void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState
- 设置动画是否从当前状态开始放映。设置为YES:当动画在运行时,当前view运行中的动画位置用于新动画的起始位置;设置为NO:在新动画开始之前,运行中的动画结束,即新动画使用最后的view位置作为开始状态。
- 若当前没有运行中或者出发了一个动画块,则该方法没有任何作用。
- +(void)setAnimationStartDate:
- 设置当前动画快的开始时间
- +(void)setAnimationTransition:(UIViewAnimationTransition) transition forView:(UIView *)view cache:(BOOL)cache
- 设置view在一个动画块中的过度。transition定义:
- 设置view在一个动画块中的过度。transition定义:
- +(void)setAnimationWillStartSelector:(SEL)selector
- 当动画开始时,设置发送到动画代理的消息
- +(void)setAnimationCurve:(UIViewAnimationCurve)curve
- 设置当一个动画块中动画属性改变时的曲线。该方法必须在beginAnimations:context和commitAnimations之间调用。
- +(void)setAnimationDelay:(NSTimeInterval)delay
- 设置动画块中动画属性改变前需要等待的时间。该方法必须在beginAnimations:context和commitAnimations之间调用。
- +(void)setAnimationDelegate:(id)delegate
- 设置动画消息的代理,可以指定当动画开始或结束时希望接收消息情况下的动画代理。而delegate是一个定义使用setAnimationWillStartSelector:和setAnimationDidStopSelector:方法的注册方法。view在动画周期中维护了对该对象的强引用。
- +(void)setAnimationDidStopSelector:(SEL)selector
- 设置当动画结束时发送给动画代理的消息
- selector的格式:
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *context)
- 其中finished包含一个BOOL值。YES:在停止之前动画运行完成;NO:其他情况
- +(void)setAnimationDuration:(NSTimeInterval)duration
- 设置一个动画块中动画的持续时间,单位为秒(seconds)。
- +(void)setAnimationRepeatAutoreverses:(BOOL)repeatAutireverses
- 设置一个动画块中德动画是否自动反转。如果设置autoreversing,单个动画周期在动画过程中改变的属性值会回到初始值。在动画结束时,受影响的视图会立即更新映射的新值。
- 如果将该函数与setAnimationRepeatCount:结合,可以创建指定循环次数的动画。另外,需要记住repeat count表示完成周期的个数。
- +(void)setAnimationRepeatCount:(float)repeatCount
- 设置一个动画块中,动画重复的次数。
相关
在transition过程中改变view的现实
- 开启一个动画块
- 在容器view中设置transition
- 从容器view中移除子视图
- 将新的子视图移动到容器视图中
- 提交动画块