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框架结构?
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控件。
        控制器的数据传递(顺传)
    2. 逆传:
      • 控制器的跳转方向:A->B。
      • 数据的传递方向:B->A。
      • 数据的传递方式:让A成为B的代理,在B中调用A的代理方法,通过代理方法的参数传递数据给A。


        控制器的数据传递(逆传)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容