信息内容
您现在的位置:首页-信息内容
UIView和UIViewController的区别与关系 发布日期:2018-5-26 来源:简书 【关闭】

1. UIViewController

一个控制器,管理一个大界面
负责界面的创建、事件处理等


I. 创建控制器

直接创建

MyViewController *vc = [[MyViewController alloc] init];

通过 xib 创建

  • 将创建的 xib 的 File's Owner 属性设为自定的控制器类
  • 将其中的一个 view 设为 File's Owner 的 view
  • 使用以下代码创建控制器

MyViewController *vc = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];

通过 storyboard 创建

// 1. 先加载storyboard文件 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"storyboardName" bundle:nil]; 

// 2. 初始化storyboard中的控制器 

// 2.1 初始化 箭头所指的控制器 MyViewController *vc = [storyboard instantiateInitialViewController]; 

// 2.2 初始化 标识my对应的控制器 MyViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"my"];


II. 控制器 MyViewController 以及 其 view 的加载过程

  1. 看 loadView 方法是否实现,是,则 使用 loadView 自定义 view,到步骤 7
  2. 若 1 没有实现,看是否从 storyboard 加载,是,则 根据 storyboard 描述创建,到步骤 7
  3. 若 2 没有实现,看是否给 nibName 赋值,是,则 根据 nibName 的值加载 xib 文件,到步骤 7
  4. 若 3 没有实现,看是否存在 MyView.xib 文件「控制器名去掉 Controller」,是,则 加载文件,到步骤 7
  5. 若 4 没有实现,看是否存在 MyViewController.xib 文件,是,则 加载文件,到步骤 7
  6. 若 5 没有实现,创建一个空的 view到步骤 7
  7. 执行 viewDidLoad 函数后,返回一个 view 给控制器

// nibName 为 MyViewController MyViewController *vc = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil]; 

// nibName 为 nil MyViewController *vc = [[MyViewController alloc] init];

注:

  • 先在 loadView 方法里给 控制器的 view 赋值
  • 还可以在 viewDidLoad 方法里等 view 加载完毕后
    重新给 控制器的 view 赋新值,不过这是第二次赋值相对耗费性能


III. 控制器 view 的加载方式

  • 控制器的 view 是延迟加载的:用到时再加载
  • 可以用 isViewLoaded 方法判断一个 UIViewController 的 view 是否已经被加载
  • 控制器的 view 加载完毕就会调用 viewDidLoad 方法


2. 多控制器管理

当控制器有多个的时候,建议控制器之间建立层级关系

I. UINavigationController

作用:管理多个控制器
使用步骤

  • 初始化 UINavigationController 对象
  • 设置 UIWindow 的rootViewController是 UINavigationController
  • 通过push方法添加 子控制器

UINavigationController 以栈的形式保存子控制器

  • 常用方法

// 栈中的所有子控制器,可以赋值 

@property(nonatomic,copy) NSArray *viewControllers; 

// 栈中的所有子控制器,不可以赋值 

@property(nonatomic,readonly) NSArray *childViewControllers; 

// 使用push方法能将某个控制器压入栈 

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated; 

// 使用add方法同样能将某个控制器压入栈,只不过没有动画 

- (void)addChildViewController:(UIViewController *)viewController; 

// 使用pop方法可以将栈顶的控制器移除,出栈的控制器会被销毁 

- (UIViewController *)popViewControllerAnimated:(BOOL)animated; 

// 回到指定的子控制器 

- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated; 

// 回到根控制器(栈底控制器) 

- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated;


控制器的加载步骤

// 1. view加载完毕「一个控制器只调用一次」 

- (void)viewDidLoad; 

// 2. view即将显示到window上 

- (void)viewWillAppear:(BOOL)animated; 

// 3. view显示完毕(已经显示到窗口) 

- (void)viewDidAppear:(BOOL)animated; 

// 4. view即将从window上移除(即将看不见) 

- (void)viewWillDisappear:(BOOL)animated; 

// 5. view从window上完全移除(完全看不见) 

- (void)viewDidDisappear:(BOOL)animated; 

// 6. 如果接收到内存警告的时候「应用代理对象先接收到警告,然后传给根控制器内存警告」 

- (void)didReceiveMemoryWarning 

/* 控制器警告方法执行步骤 1. 判断控制器内有无 View,有,到 1 2. 判断控制器内的 View 能否销毁「是否显示在窗口上」,能,到 2 3. 执行 viewWillUnload 4. 控制器的 View 被销毁 5. 执行 viewDidUnload 

*/ 

// --------- 和内存有关的方法 ------------------------------ // 

7. view即将销毁的时候调用 

- (void)viewWillUnload{ 

    // 「ARC模式下」控制器内的view对象即将销毁,在它销毁前清空下View中的内容 self.valueName = nil

    // 写nil ARC和MRC 都会清空一下对应的属性 

    // 仅在 ARC 下 还可以使用 [self.valueName release]; 

// 8. view销毁完毕的时候调用 

- (void)viewDidUnload;


II. UITabBarController

使用步骤

  • 初始化 UITabBarController 对象
  • 设置 UIWindow 的rootViewController为 UITabBarController
  • 通过 addChildViewController方法添加对应个数的子控制器

添加控制器

  • 添加单个子控制器
    - (void)addChildViewController:(UIViewController *)childController;
  • 设置子控制器数组
    @property(nonatomic,copy) NSArray *viewControllers;

特性

  • 如果 UITabBarController 有 N 个子控制器,那么 UITabBar 内部就会有 N 个 UITabBarButton 作为子控件
Paste_Image.png
  • UITabBarButton 里面显示什么内容,由对应子控制器的 tabBarItem 属性决定


III. Segue

简介:操作界面跳转的 UIStoryBoardSegue对象
属性

// 表示是哪个 Segue 的唯一标识 

@property (nonatomic, readonly) NSString *identifier; 

// 来源控制器「从哪里开始跳转界面」

@property (nonatomic, readonly) id sourceViewController;

// 目标控制器「跳转到那个界面」 

@property (nonatomic, readonly) id destinationViewController;

使用步骤

  1. 在 StoryBoard 上拖线,表明来源控制器和目标控制器
Paste_Image.png

手动拖线

Paste_Image.png
  1. 给拖好的线 Segue 设置一个 唯一标识
Paste_Image.png
  1. 使用perform方法执行对应的Segue

// Segue必须由来源控制器来执行,也就是说,这个perform方法必须由来源控制器来调用 [self performSegueWithIdentifier:@"Segue的唯一标识名" sender:nil];


IV. 补充

1)performSegueWithIdentifier:sender: 方法的完整执行过程

  1. 根据identifier去storyboard中找到对应的线,新建UIStoryboardSegue对象

    • 设置Segue对象的sourceViewController(来源控制器)
    • 新建并且设置Segue对象的destinationViewController(目标控制器)
  2. 调用sourceViewController的下面方法

    • 做一些跳转前的准备工作并且传入创建好的Segue对象
      这个sender是当初 performSegueWithIdentifier:sender:中的sender
      - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
  3. 调用Segue对象的- (void)perform;方法开始执行界面跳转操作

    • 如果segue的style是push
      取得sourceViewController所在的UINavigationController
      调用UINavigationController的push方法将destinationViewController压入栈中,完成跳转
    • 如果segue的style是modal
      调用sourceViewController的presentViewController方法将destinationViewController展示出来


2)Modal 简介

  • 默认效果:从屏幕底部往上钻,直到盖住之前的控制器为止
  • 以Modal的形式展示控制器

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion

  • 关闭当初Modal出来的控制器

- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion;


3. UIView

I. UIView 的显示步骤

  1. view 内部的 Layer 会准备好一个CGContextRef「图层类型上下文」
  2. 调用 delegate「这里就是 UIView」的drawLayer:inContext:方法
    传入已经准备好的CGContextRef 对象
  3. view 在drawLayer:inContext:方法中又会调用自己的drawRect:方法
  4. view 就可以在drawRect:方法中实现绘图代码, 所有东西最终都绘制到 view.layer 上面
  5. 系统再将 view.layer 的内容拷贝到屏幕, 于是完成了 view 的显示


II. 系统自动调用的方法「留给子类去实现」

// 控件的frame发生改变的时候就会调用 

// 一般在这里重写布局子控件的位置和尺寸 

// 重写了这个写方法后,一定调用 [super layoutSubviews]; 

- (void)layoutSubviews; 

- (void)didAddSubview:(UIView *)subview; 

- (void)willRemoveSubview:(UIView *)subview; 

- (void)willMoveToSuperview:(UIView *)newSuperview; 

- (void)didMoveToSuperview; 

- (void)willMoveToWindow:(UIWindow *)newWindow; 

- (void)didMoveToWindow;


III. 响应接口

@interface UIView : UIResponder<NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem> 

// 能否和用户进行交互「默认 能」 

@property(nonatomic,getter=isUserInteractionEnabled) BOOL userInteractionEnabled; 

// 控件的一个标记:父控件可以通过tag找到对应的子控件 

@property(nonatomic) NSInteger tag; 

// 图层:可以用来设置 圆角\阴影 效果 

@property(nonatomic,readonly,retain) CALayer *layer; 

// 通过一个frame来初始化一个UI控件 

- (id)initWithFrame:(CGRect)frame; 

@end


IV. 几何图形接口

@interface UIView(UIViewGeometry) 

// 位置和尺寸:以「自己」的左上角为坐标原点(0, 0) 

@property(nonatomic) CGRect bounds; 

// 位置和尺寸:以「父控件」的左上角为坐标原点(0, 0) 

@property(nonatomic) CGRect frame; 

// 中点:以「父控件」的左上角为坐标原点(0, 0) 

@property(nonatomic) CGPoint center; 

// 形变属性「平移\缩放\旋转」 

@property(nonatomic) CGAffineTransform transform;

// 是否支持多点触摸「默认 不支持」 

@property(nonatomic,getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled; 

@end


V. View 结构接口

@interface UIView(UIViewHierarchy) 

// 父控件 @property(nonatomic,readonly) UIView *superview; 

// 子控件(新添加的控件默认都在subviews数组的后面, 新添加的控件默认都显示在最上面\最顶部) 

@property(nonatomic,readonly,copy) NSArray *subviews; 

// 获得当前控件所在的window 

@property(nonatomic,readonly) UIWindow *window; 

// 从父控件中移除一个控件 - (void)removeFromSuperview; 

// 添加一个子控件(可以将子控件插入到subviews数组中index这个位置) 

- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index; 

// 交换subviews数组中所存放子控件的位置 

- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2; 

// 添加一个子控件(新添加的控件默认都在subviews数组的后面, 新添加的控件默认都显示在最上面\最顶部) 

- (void)addSubview:(UIView *)view; 

// 添加一个子控件view(被挡在siblingSubview的下面) 

- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview; 

// 添加一个子控件view(盖在siblingSubview的上面) 

- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview; 

// 将某个子控件拉到最上面(最顶部)来显示 

- (void)bringSubviewToFront:(UIView *)view; 

// 将某个子控件拉到最下面(最底部)来显示 

- (void)sendSubviewToBack:(UIView *)view; 

// 判断view的子控件 或者 子控件的子控件 是否为view的后代,默认自己也是自己的后代 

- (BOOL)isDescendantOfView:(UIView *)view; 

// returns YES for self. 

// 通过tag获得对应的子控件 

// 也可以或者子控件的子控件,循环遍历的方式,也遍历自己,性能不好 

- (UIView *)viewWithTag:(NSInteger)tag; 

@end


VI. 渲染接口

@interface UIView(UIViewRendering) 

// 超出控件边框范围的内容是否都剪掉 

@property(nonatomic) BOOL clipsToBounds; 

// 背景色「默认 nil」 

@property(nonatomic,copy) UIColor *backgroundColor; 

// 透明度「0.0~1.0,默认 1.0」 

@property(nonatomic) CGFloat alpha; 

// 是否不透明,是 则 不透明「默认 不透明」 

@property(nonatomic,getter=isOpaque) BOOL opaque; 

// 是否隐藏,是 则 隐藏 

@property(nonatomic,getter=isHidden) BOOL hidden; 

// 内容模式(居中/填充/拉伸)「默认 填充,UIViewContentModeScaleToFill」 

@property(nonatomic) UIViewContentMode contentMode; @end


VII. Block 动画接口

@interface UIView(UIViewAnimationWithBlocks)

 + (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;

 + (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;

 + (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;

 + (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion; 

@end


成都世帆软件    交通运输综合执法系统软件、公路路政执法系统软件、道路运政执法系统软件、海事行政、水路运政、航道行政、港口行政执法 管理系统软件定制开发

交通综合执法系统、公路路政执法管理系统、超限运输管理系统、道路运政执法管理系统、运管执法管理系统、公路养护管理系统、公路运行监测系统
市场监管执法软件、工商行政执法软件、环境监察执法软件、城市管理执法软件、食品卫生执法软件

备案号:蜀ICP备12010221号-20    电-话:028-8768 9944