美文网首页iOS-UIobject C学习
UIView 和 UIViewController

UIView 和 UIViewController

作者: _凉风_ | 来源:发表于2016-06-23 17:28 被阅读354次

    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
    

    相关文章

      网友评论

        本文标题:UIView 和 UIViewController

        本文链接:https://www.haomeiwen.com/subject/bqfodttx.html