UI控件进阶2——多控制器管理


控制器及View的多种创建方式

  • 创建控制器的3种方式?
    1. 直接通过alloc + init的方式创建。
      • 创建一个“Single View Application”,删除默认控制器、Main.storyboard、Main Interface设置为空。
      • 创意一个自定义的控制器,FirstViewController。
      • 在AppDelegate的application:didFinishLaunchingWithOptions:方法中创建UIWindow对象。
      • 通过alloc + init的方式创建该控制器的对象,并设置该控制器view的背景色。
      • 设置UIWindow的根控制器为该控制器对象。
    2. 通过加载storyboard文件来创建一个控制器。
      • 删除了Main.storyboard文件,也清空了Main Interface的配置,那么现在就需要自己创建一个新的storyboard文件(Two.storyboard), 然后拖一个控制器上去,在AppDelegate中自己写代码来加载Two.storyboard文件。
    3. 通过指定的xib文件来创建控制器。
      • 创建一个自己的控制器类。
      • 创建一个xib文件,在xib文件中拽一个UIView。
      • 选中xib文件中的“File's Owner”,在属性中设置对应的类(Class)是刚才创建的控制器类。“File's Owner”可以理解为,当前xib文件是为谁服务的。
      • 然后选中“File's Owner”->“右击”选中“view”->拖线到对应的view上。(设置该xib文件中哪个视图是控制器默认要创建的视图)
      • 通过alloc + initWithNibName来创建。
// 一、直接通过alloc+init的方式创建
// 1.创建UIWindow
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 2.创建控制器 
FirstViewController *vc1 = [[FirstViewController alloc] init];
vc1.view.backgroundColor = [UIColor blueColor];
// 3.设置控制器为UIWindow对象的根控器"rootViewController"                            
self.window.rootViewController = vc1;
// 4.显示UIWindow对象
[self.window makeKeyAndVisible];

// 二、通过加载storyboard文件创建
// 1.加载对应的storyboard文件
UIStoryboard *myStoryboard = [UIStoryboard storyboardWithName:@"My" bundle:nil];
// 2.创建该storyboard中的被设置为"初始化控制器"(箭头所指向的控制器)的对象。
UIViewController *vc2 = [myStoryboard instantiateInitialViewController];
// 3.根据storyboard中的控制器的storyboard ID来创建对应的控制器
UIViewController *vc3 = [myStoryboard instantiateViewControllerWithIdentifier:@"redVwController"];
// 4.设置控制器为UIWindow对象的根控制器"rootViewController"
self.window.rootViewController = vc2;

// 三、通过指定的 xib 文件来创建
// 1.通过xib文件, 创建控制器
FirstViewController *vc1 = [[FirstViewController alloc] initWithNibName:@"First" bundle:nil];
// 2.设置控制器为UIWindow对象的根控制器"rootViewController"
self.window.rootViewController = vc1;

  • 创建控制器中的UIView?
    1. 控制器创建好以后,控制器所管理的view是如何创建的?
      • 控制器的view是通过调用控制器的loadView方法来创建的。这个方法是UIViewController中的一个对象方法,只要控制器的loadView方法被调用了,那么证明控制器的view创建好了。
      • 当调用完毕控制器的loadView方法以后,从这时开始,才创建好了控制器的view。
      • 当控制器的view被创建好以后,紧接着就调用控制器的viewDidLoad方法。
      • 控制器的view采用了懒加载的方式,也就是说,在需要的时候(在用到的时候)才会创建(调用loadView方法)。
      • 注意:无论控制器是如何创建的,只要在控制器中,重写了loadView方法,并且没有调用[super loadView];方法,那么最终控制器的view就必须完全在loadView方法中自己来创建了,所以loadView方法可以用来自定义view。
    2. 控制器中的view创建:当第一次从self.view中获取view的时候(第一次使用self.view的时候),控制器会调用它自己的loadView方法先创建一个view,并且把这个新创建的view设置给self.view。
      • 如果是直接通过alloc + init方法创建的控制器,则self.view = [[UIView alloc] init];
      • 如果是通过storyboard创建的控制器,加载storyboard中的控制器,并把storyboard中的控制器中的view设置给self.view。
      • 如果是通过加载xib创建的控制器,加载xib中的view,并把xib中的view设置给self.view。
    3. 通过storyboard创建完控制器后,自动调用loadView方法,创建控制器的view。此时自定义的控制器,因为没有“重写”loadView方法,所以loadView方法内部就是根据storyboard文件中的view来创建view的。
    4. 通过xib文件创建完控制器后,自动调用loadView创建控制器的view。此时自定义的控制器,因为没有“重写”loadView方法,所以loadView方法内部就是根据xib文件中的view来创建view的。
      • 如果创建控制器的时候,通过initWithNibName指定了xib的名字,那么就根据该xib创建view。
      • 如果创建控制器的时候,没有指定任何xib文件,也没有相应的storyboard文件,那么会尝试查找“与控制器名字相同的,但是去除Controller的文件名的xib文件”,如果还是没有,会尝试查找与控制器名字完全相同的xib文件,如果有,则使用该xib文件创建view。
      • 建议:如果要使用某个xib文件名自动匹配的方式创建view,建议名字与控制器相同。
    5. 通过重写UIViewController的loadView方法,自己通过代码来创建控制器的view。
      • 控制器的loadView方法就是用来自定义view的。如果要为控制器自定义view,要写在loadView中,不要写在viewDidLoad中。
      • 如果重写loadView方法中调用了[super loadView];,那么依然会使用默认的方式来加载。想自定义,应该不调用此方法。
    6. 无论是通过加载xib创建view,storyboard创建view,最终都依赖于loadView方法。
    7. 控制器的loadView方法什么时候调用?
      • 在需要用到控制器的view的时候才调用,当调用UIWindow对象的makeKeyAndVisible方法时,就需要显示该view了,此时就表示用到view了,这个就叫做“延迟加载”。

多控制器管理

  • 多控制器管理?
    1. 多控制器管理的思路:使用一个控制器来管理所有其他控制器,类似于使用一个UIView来管理其他的子view。
    2. 父控制器:管理其他控制器的控制器,就可以看做是“父控制器”、子控制器:被管理的控制器就是子控制器。
    3. iOS提供了两个比较特殊的控制器(用来管理“控制器”的控制器):
      • UINavigationController导航控制器,轻松管理多个控制器,并且控制不同控制器之间的跳转和切换。
      • UITabBarController也可以轻松地管理多个控制器,轻松完成控制器之间的切换。

  • UINavigationController导航控制器?
    1. 使用步骤:
      • 创建、初始化一个导航控制器:UINavigationController。
      • 设置UIWindow的rootController为UINavigationController。
      • 通过调用push方法添加子控制器到UINavigationController。
      • 通过pop方法可以返回到上一个控制器。
      • 注意:谁是最后一个push进来的,当前显示的就是哪个viewController。
    2. 导航控制器的导航栏是从Y坐标20开始的,高度是44,导航栏上面的20高度是“状态栏”。导航栏的内容由栈顶控制器的navigationItem属性决定。
    3. UINavigationController导航控制器以栈的形式保存的子控制器。
@property(nonatomic,copy) NSArray *viewControllers;
@property(nonatomic,readonly) NSArray *childViewControllers;
// 使用push方法能将某个控制器压入栈
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;

// 使用pop方法可以移除栈顶控制器
// 将栈顶的控制器移除
- (UIViewController *)popViewControllerAnimated:(BOOL)animated;
// 回到指定的子控制器
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
// 回到根控制器(栈底控制器)
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated;

// 左上角的返回按钮
@property(nonatomic,retain) UIBarButtonItem *backBarButtonItem;
// 中间的标题视图
@property(nonatomic,retain) UIView *titleView;
// 中间的标题文字
@property(nonatomic,copy) NSString *title;
// 左上角的按钮
@property(nonatomic,retain) UIBarButtonItem *leftBarButtonItem;
// 右上角的按钮
@property(nonatomic,retain) UIBarButtonItem *rightBarButtonItem;

  • UITabBarController?
    1. 使用步骤:
      • 初始化UITabBarController。
      • 设置UIWindow的rootViewController为UITabBarController。
      • 根据具体情况,通过addChildViewController方法添加对应个数的子控制器。
    2. 如果UITabBarController有N个子控制器,那么UITabBar内部就会有N个UITabBarButton作为子控件。
// 添加单个子控制器
- (void)addChildViewController:(UIViewController *)childController;
// 设置子控制器数组
@property (nonatomic,copy) NSArray *viewControllers;
// 标题文字
@property(nonatomic,copy) NSString *title;
// 图标
@property(nonatomic,retain) UIImage *image;
// 选中时的图标
@property(nonatomic,retain) UIImage *selectedImage;
// 提醒数字
@property(nonatomic,copy) NSString *badgeValue;


  • App主流UI框架结构?
UI控件进阶2——多控制器管理_第1张图片
App主流UI框架结构

  • Segue的介绍?
    1. storyboard上每一根用来界面跳转的线,都是一个UIStoryboardSegue对象,简称Segue,表示延续、继续的意思。
    2. 每一个segue对象,都有3个属性:①唯一标识;②来源控制器;③目标控制器。
    3. 根据segue的执行(跳转)时刻,segue可以分为2大类型:
      • 自动型:点击某个控件后,自动执行segue,自动完成界面跳转。
      • 手动型:需要通过写代码手动执行segue,才能完成界面跳转。
    4. 自动型segue:
      • 按住control键,直接从控件拖线到目标控制器。
      • 如果点击某个控件,不需要做任何判断,直接跳转到下一个界面,建议使用“自动型segue”。
    5. 手动型segue:
      • 按住control键,从来源控制器拖线到目标控制器。
      • 手动型的segue需要设置一个标识Identifier。
      • 如果点击某个控件,需要做一些处理之后才能跳转到下一个界面,建议使用“手动型segue”。
    6. 利用某个控制器的performSegueWithIdentifier:对象方法可以执行当前控制器的某个Segue,跳转界面:
      • self是来源控制器,只能通过来源控制器来调用该方法。
      • 根据Identifier去storyboard中找到对应的线,新建UIStoryboardSegue对象。
      • 设置Segue对象的sourceViewController(来源控制器)。
      • 新建并且设置Segue对象的destinationViewController(目标控制器)。
    7. 调用sourceViewController来源控制器的- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;方法,做跳转前的准备工作并传入创建好的Segue对象。
      • sender就是调用performSegueWithIdentifier:sender:方法时传入的对象。
      • 调用Segue对象的- (void)perform;方法开始执行界面跳转操作。
      • 如果Segue的style是push,则取得sourceViewController所在的UINavigationController,调用UINavigationController的push方法将destinationViewController压入栈中,完成跳转。
      • 如果Segue的style是modal调用sourceViewController的presentViewController方法将destinationViewController展示出来。

  • Modal介绍?
    1. 除了push之外,还有另一种控制器的切换方式,那就是Modal,任何控制器都能通过modal的形式展示出来。
    2. modal的默认效果:新控制器从屏幕的最底部往上钻,直到盖住之前的控制器为止。
// 以modal的形式展示控制器
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion;
// 关闭当初modal出来的控制器
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion;

  • 控制器的数据传递
    1. 顺传:
      • 控制器的跳转方向:A->B。
      • 数据的传递方向:A->B。
      • 数据的传递方式:在A控制器的prepareForSegue:sender:方法中根据Segue参数取得destinationViewController,也就是控制器B,直接给控制器B传递数据。
      • 在B的viewDidLoad方法中取得数据,或者利用setter方法,设置界面上的UI控件。
        UI控件进阶2——多控制器管理_第2张图片
        控制器的数据传递(顺传)
    2. 逆传:
      • 控制器的跳转方向:A->B。
      • 数据的传递方向:B->A。
      • 数据的传递方式:让A成为B的代理,在B中调用A的代理方法,通过代理方法的参数传递数据给A。


        UI控件进阶2——多控制器管理_第3张图片
        控制器的数据传递(逆传)

你可能感兴趣的:(UI控件进阶2——多控制器管理)