Objective-C 之UIView

UIView简介

UIView表示屏幕上的一块矩形区域,它在App中占有绝对重要的地位,因为iOS中几乎所有可视化控件都是UIView的子类。负责渲染区域的内容,并且响应该区域内发生的触摸事件。

UIView的功能

1、管理矩形区域里的内容
2、处理矩形区域中的事件
3、子视图的管理
4、还能实现动画 UIView的子类也具有这些功能

UIView类的层次关系

《Objective-C 之UIView》 UIView类的层次关系

UIView的三个结构体

先学习三个结构体:CGPointCGSizeCGrect
确定UIView的位置和大小。
这三个结构体均在一个头文件里:CGGeometry.h

1. CGPoint

struct CGPoint {  
  CGFloat x;  
  CGFloat y;  
};  

typedef struct CGPoint CGPoint;  

2.CGSize

struct CGSize {  
  CGFloat width;  
  CGFloat height;  
};  

typedef struct CGSize CGSize;  

3.CGRect

struct CGRect {  
  CGPoint origin;  //偏移是相对父视图的  
  CGSize size;  
}; 

typedef struct CGRect CGRect;  

《Objective-C 之UIView》 UIView 的坐标规则

UIView的常用属性

//描述当前视图在父视图中的位置和大小
@property(nonatomic) CGRect frame;
  • frameCGRect frameorigin是相对于父视图的左上角原点(0,0)的位置,改变视图的frame会改变center
//描述当前视图在其自身坐标系统中的位置和大小
@property(nonatomic) CGRect bounds;
  • boundsCGRect是告诉子视图本视图的原点位置(通俗的说就是,子视图的frameorigin与父视图的boundsorigin的差,就是子视图相对于父视图左上角的位置,如果结果为负,则子视图在父视图外)
//描述当前视图中心点在父视图中的位置
@property(nonatomic)CGPoint center;
  • centerCGPoint指的就是整个视图的中心点,改变视图的center也会改变frame
  • framecenter都是相对于父视图的,bounds是相对于自身的。
//形变属性(平移\缩放\旋转)
@property(nonatomic)CGAffineTransform  transform;
//default is CGAffineTransformIdentity
//YES:支持多触点
@property(nonatomic,getter=isMultipleTouchEnabled)BOOL multipleTouchEnabled; //default is NO
//YES:超出控件边框范围的内容都剪掉
@property(nonatomic)BOOL clipsToBounds;
//背景色
@proprety(nonatomic,copy)UIColor *backgroundColor;
//default is nil;
//透明度(0.0~1.0)
@property(nonatomic)CGFloat alpha;
//default is 1.0
//YES:不透明 NO:透明
@property(nonatomic,getter=isOpaque)BOOL  opaque;
//default is YES
//YES:隐藏  NO:显示
@property(nonatomic,getter=isHidden)BOOL  hidden;
//内容模式
@property(nonatomic) UIViewContentMode contentMode
//default is UIViewContentModeScaleToFill

几个基本界面元素:window(窗口)、视图(view)

1、UIView

下面来认识一下UIView类,这个类继承自UIResponder,看这个名字我们就知道它是负责显示的画布,如果说把window比作画框的话。我们就是不断地在画框上移除、更换或者叠加画布,或者在画布上叠加其他画布,大小当然 由绘画者来决定了。有了画布,我们就可以在上面任意施为了。很多简单的东西我会把库里面的内容贴出来,如果东西太多贴出来就不太好,朋友们自己去库文件里面看吧。这个类在UIView.h里面。下面我们先学习一些基础的东西,其他的东东会在以后慢慢展开。

UIView* myView =[[ UIView alloc]
           initWithFrame:CGRectMake(0.0,0.0,200.0,400.0)];
//这里创建了一块画布,定义了相对于父窗口的位置, 以及大小。
2、UIWindow

UIWindow继承自UIView,关于这一点可能有点逻辑障碍,画框怎么继承自画布呢?不要过于去专牛角尖,画框的形状不就是跟画布一样吗?拿一块画布然后用一些方法把它加强,是不是可以当一个画框用呢?这也是为什么一个view可以直接加到另一个view上去的原因了。
看一下系统的初始化过程(在application didFinishLauchingWithOptions里面):

self.window = [[[UIWindow alloc] 
initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

self.window.backgroundColor = [UIColor grayColor];
//给window设置一个背景色

[self.window makeKeyAndVisible];
//让window显示出来
3、UIScreen类代表了屏幕,通过这个类我们可以获取一些想要
CGRect screenBounds = [ [UIScreen mainScreen]bounds];
//返回的是带有状态栏的Rect 
CGRect viewBounds = [ [UIScreen mainScreen]applicationFrame];
//不包含状态栏的Rect  
//screenBounds 与 viewBounds 均是相对于设备屏幕来说的  
//所以 screenBounds.origin.x== 0.0 ;
//screenBounds.oringin.y = 0.0;
screenBounds.size.width == 320;
screenBounds.size.height == 480;//(或者其他分辨率有所差异)  
//所以 screenBounds.origin.x== 0.0 ;
//screenBounds.oringin.y = 20.0;(因为状态栏的高度是20像素)  
//screenBounds.size.width == 320;
//screenBounds.size.height == 480;
//取得StatusBar的位置和大小
[self.view addSubview:theToolbar];
CGRect statusBarRect = [[UIApplication sharedApplication]statusBarFrame];  

NSLog(@\"%@\", NSStringFromCGRect(statusBarRect));

UIView的常用方法

  • addSubview: 添加一个子视图到接收者并让它在最上面显示出来。
- (void)addSubview:(UIView *)view 
//添加一个子视图到接收者并让它在最上面显示出来。

这个方法同样设置了接收者为下一个视图响应对象。接收者保留视图。如果你使用removeFromSuperview方法用来把视图移除他的显示列表,那么视图将会被释放。如果你想要在视图移除显示列表後保留并使用这个视图(如果,举个例子,你想要交换一些视图的位置。),你不许保留那个视图在他调用removeFromSuperview前。

  • bringSubviewToFront: 把指定的子视图移动到顶层
- (void)bringSubviewToFront:(UIView *)view 
//把指定的子视图移动到顶层 
//将view往前移动一个图层(与它的前一个图层对调位置)
  • convertPoint:fromView: 把一个点从一个坐标系转换到接收者的坐标系
- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view 
/*
参数:
point:一个视图中坐标系上的点 
view:一个视图包含了点和他自身坐标系。如果是图是nil,那么这个方法将尝试转换基于窗口的坐标系。
      否则视图和那个接收者必须属于同一个UIWindow对象。 
返回值 :一个转换到接收者坐标系的点 
功能:把一个点从一个坐标系转换到接收者的坐标系 
*/
  • convertPoint:toView: 转换一个点从接收者坐标系到给定的视图坐标系
- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view 
/*
参数 :
point :一个在调用者坐标系中的点
 view :一个包含了需要被转换的点的视图。如果视图是nil,那么这个方法将会转换成基于窗口的坐标。
       否则视图和接收者都要属于同一个UIWindow对象。 
返回值: 基于视图的坐标系转换过的点 
功能:转换一个点从接收者坐标系到给定的视图坐标系 
*/
  • convertRect:fromView: 转换一个矩形从其他视图坐标系到接收者坐标系。
- (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view 
/*参数:
rect: 一个在视图坐标系中的矩形 
view: 一个视图内部有矩形在他的坐标系中。如果视图是nil,那么这个方法将会基于窗口来转换。
      否则视图和接收者必须都属于同一个UIWindow对象 
返回值 : 转换过的矩形
*/
  • convertRect:toView: 转换接收者坐标系中的矩形到其他视图
 - (CGRect)convertRect:(CGRect)rect toView:(UIView *)view 
/*参数:
rect:一个在接收者坐标系中的矩形 
view: 要转换过去的目标视图对象。如果这个是视图是nil,这个方法将会基于窗口坐标系来转换。
     否者视图和接收者必须属于同一个UIwindow对象
返回值:一个转换过的矩形*/
  • didAddSubview: 告诉视图当子视图已经添加
- (void)didAddSubview:(UIView *)subview 
/*参数
subview :被添加做子视图的视图对象 
讨论: 
  被子类重写用来执行额外的命令当子视图添加到接收者。这个方法被addSubview调用*/
  • didMoveToSuperview 通知接收者父视图已经改变(nil是允许的)
- (void)didMoveToSuperview

默认不做任何事情;子类可以重写这方法来作为特定的实现

  • didMoveToWindow 通知接收者它一斤给添加到窗口中
- (void)didMoveToWindow 

默认实现不做任何事情;子类可以重写这个方法来做特殊的实现。
窗口的属性有可能是nil当这个方法调用的时候,这表明接收者并不属于当然任何一个窗口。
这个只发生在接收者从它的父视图上移除或者接收者添加到父视图中而不是添加到window中。
重写这个方法可以用来选择忽略一些他们不关心的对象。

  • drawRect: 在接收者视图中绘制矩形
 - (void)drawRect:(CGRect)rect
/* 参数 rect 一个定义的需要绘制的矩形 */

子类重写这个方法如果他们确实要绘制他们自定义的视图。
如果子类是其他视图的容器那么它不需要重写这个方法。默认的实现不做任何事情。如果你自定义的视图是一个UIView子类,你不需要去调用它的父类实现。
注意如果它的父类实现绘制并且不透明属性为YES那么每一个子类都需要填充矩形。
当这个方法被调用,接收者可以假定他的帧在坐标上已经转换,边界矩形已经应用;所有他要做的就是绘制自定义的方法。
使用UIGraphicsGetCurrentContext方法去获取当前图形内容用来绘制,坐标原点在左上角。不要保留图片内容当他可以被drawRect:这个方法调用。

  • exchangeSubviewAtIndex:withSubviewAtIndex: 交换接收者的子视图和给定的索引视图
 - (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2
/* 参数:
 index1 一个需要取代索引2的子视图 
  index2 一个需要取代索引1的子视图*/
  • hitTest:withEvent: 返回接收者视图层次中最远的派生(包括它本身)的特定的点。
 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
/*参数:
 point :接收者坐标系中的点 
event: 触发这个方法的事件或者是如果这个方法被预调用就返回nil 
返回值: 一个视图对象最远的派生点。如果这个点位于接收者之外就返回nil */

讨论 这个方法贯穿视图的层次发送pointInside:withEvent: 消息到每一个子视图用来决定那个子视图需要接收触摸事件。
如果pointInside:withEvent: 返回YES,那么视图的层次全部贯穿;否则视图层次的分支是被否定的。
你不太需要调用这个方法,但是你需要重写它用来隐藏子视图的触摸事件。 如果视图是隐藏的,禁止用户交互的或者透明值小于01那么这个方法不可用。

initWithFrame: 初始化并返回一个新的拥有特定帧矩形的视图对象

 - (id)initWithFrame:(CGRect)aRect 
/*参数:
aRect 一个帧矩形用来创建视图对象。原始的帧在它的父视图的坐标系中。设置这个属性用来改变中心和边界属性。 
返回值: 一个初始化的视图对象,如果没有被创建那就返回nil */

一个新的视图对象必须添加到视图链中才能使用。这个方法为UIView类指出初始化对象。

  • insertSubview:aboveSubview: 在视图层次顶层插入一个视图
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview
/*参数
view :一个插入被用来放在顶层的视图。它将会从父视图中移除如果它不是相邻视图
siblingSubview: 一个相邻视图用来放在插入视图的後面 */
  • insertSubview:atIndex: 插入视图到指定的索引
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index 
参数: 
view 插入的视图,这个值不能是nil 
index 子视图索引从0开始并且不能大于子视图的数量 
  • insertSubview:belowSubview:插入视图到显示链的底层
- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview
/*参数:
view: 一个需要插入到其他视图底部的视图。它将从它的父视图移除如果它不与相邻视图的相邻
siblingSubview:一个相邻视图将会在插入的视图之上
  • isDescendantOfView:返回一个布尔值指出接收者是否是给定视图的子视图或者指向那个视图
- (BOOL)isDescendantOfView:(UIView *)view 
/*参数:
view :一个视图用来测试子视图在视图层次中的关系 
返回值: 如果接收者是视图的子视图就返回YES,或者视图就是接收者;否则就是NO*/
  • layoutIfNeeded 排列子视图如果需要的话
- (void)layoutIfNeeded 

使用这个方法来关注子视图的排列在绘制前

  • layoutSubviews 排列子视图
- (void)layoutSubviews 

当layoutIfNeeded被调用是子类用来重写这个方法来排列子视图。默认实现这个方法不做任何事情。

  • pointInside:withEvent: 返回一个布尔值指出接收者是否包含特定的点
 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 
/*参数
point:一个在接收者坐标系内的点 
event:这个方法的目标事件或者如果这个方法被预调用返回nil 
返回值:如果点在接收者边界内返回YES,否则返回NO*/
  • removeFromSuperview 把接收者从它的父视图或者窗口移除,并在响应链中移除。
 - (void)removeFromSuperview 

接收者同时释放;如果你计划重用它,要确定在发送消息前保持它并在添加到其他UIView对象作为子视图後移除。 不要在显示的时候调用

  • sendSubviewToBack: 移动指定的子视图到它相邻视图的後面
 - (void)sendSubviewToBack:(UIView *)view 
/*参数 :view 一个子视图用来移动到它後面去*/
  • setNeedsDisplay 控制接收者的边界矩形被标记为需要显示
-(void)setNeedsDisplay 

默认情况下,视图几何图形的改变自动重绘而不需要调用drawRect:方法。因此,你需要去请求视图重绘当视图的数据或者状态改变的时候。从这个意义上来说,向视图发送setNeedsDisplay消息。任何UIView对象标记为需要显示後将会在应用程序循环中自动重新绘制。

  • setNeedsDisplayInRect: 标记接收者中的特定的矩形区域为需要显示,或者添加接收者现有的其他无效区域
 - (void)setNeedsDisplayInRect:(CGRect)invalidRect
/*参数: invalidRect 标记接收者的矩形区域为无效的;他需要在接收者坐标系中定义。*/

默认情况下,视图几何图形的改变自动重绘而不需要调用drawRect:方法。因此,你需要去请求视图重绘当视图的数据或者状态改变的时候。使用这个方法或者用setNeedsDisplay方法来标记视图需要显示的地方。

  • setNeedsLayout 设置当子视图显示的时候需要重新排列
- (void)setNeedsLayout

如果你调用这个方法在下一个显示方法之间,那么layoutIfNeeded排列子视图;否则将不会做任何事情

  • sizeThatFits: 计算并返回一个最好的适应接收者子视图的大小
 - (CGSize)sizeThatFits:(CGSize)size
/* 参数
 size :接收者首选的尺寸 
返回值:一个新的大小用来适应接收者子视图 

默认的实现返回大小参数 子类重写这个方法用来返回特定视图的大小。举个粒子,UISwitch返回一个修正过的大小,UIImageView返回图片的大小 这个方法并没有改变接收者的大小

  • sizeToFit 调整大小并移动接收者视图大小所以他包含了他的子视图
 - (void)sizeToFit 

这个方法使用sizeThatFits: 方法来决定大小。子类需要重写sizeThatFits:用来计算正确的尺寸大小。默认的实现不做任何事情。

viewWithTag: 返回视图的特定的标签

- (UIView *)viewWithTag:(NSInteger)tag 
参数: 
/*tag: 一个用来在视图中搜索的标签 
返回值: 视图在接收者层次中符合的标签,接收者也包含在搜索中。 */
  • willMoveToSuperview: 通知接收者他的父视图将会改变到特定的父视图(也有可能是nil)
 - (void)willMoveToSuperview:(UIView *)newSuperview 
/*参数 :
newSuperview 新的视图对象将会是接收者新的父视图 */

子类可以重写这个方法来做一些特定的行为

  • willMoveToWindow: 通知接收者它已经被添加到特定的窗口对戏那个的视图层次中(也有可能是nil)
 - (void)willMoveToWindow:(UIWindow *)newWindow 
/*参数 :
newWindow 一个窗口对象将会成为接收者新的视图层次的根视图 */

讨论 子类可以重写这个方法来提供一些特定的必要实现

  • willRemoveSubview: 由子类重写用来在子视图从接收者视图中移除前执行一些特定的方法。
- (void)willRemoveSubview:(UIView *)subview 
/*参数:
subview: 子视图将会被移除*/

讨论 这个方法被调用当子视图接收到removeFromSuperview消息或者子视图从接收者视图层次中移除因为它要被添加到其他视图了

参考资料:
UIView详解
UIView(简书1)
UIView(简书2)

    原文作者:燚随风
    原文地址: https://www.jianshu.com/p/e2617be4c930
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞