这节课的主要内容包括iPad、Split Views、Popovers及做一个universal的应用并在两种设备上运行。

UIToolbar

通常在屏幕的顶部或底部,长得像钢筋一样。一个工具栏,是一个UIBarButtonItems的集合。UIBarButtonItems不是按钮,有点像是简化过的按钮。UINavigationController有一个在底部的工具栏,可以通过在xcode里inspect Navigation Controller中的Shows Toolbar小开关打开,但工具栏上的按钮和Navigation Controller本身没有任何关系,它只和当时显示的ViewController有关。

UIBarButtonItems

是使UIToolbar真正工作的东西,他们有target action,就像一个按钮。有两个特殊的UIBarButtonItems,Fixed和Flexible space,这些都是用来安排你UIToolbar按钮的显示方式。创建一个UIBarButtonItems的方式是alloc/init,它可以采用文字或图像,或者可以用另一种叫做initWithBarButtonSystemItem的初始化方法,然后你给它在枚举类型中指定一个。

要创建一个工具栏非常简单,只需将其拖动到你的ViewController,通常会连到一个outlet,然后只需从xcode中拖个UIBarButtons到它里面,或者在代码中设置个数组,工具栏对象有个物品数组。

UISplitViewController

创建一个UISplitViewController的方法是在xcode里将它托出来,只能拖动Split View到一个ipad类型的storyboard。Split View通常只是一个基本元素,它填满整个屏幕,不可能把Split View放到其他什么的内部,一般情况下是提供给整个app的。Split View有两个ViewControllers,一个左侧一个右侧,左侧叫Master,右侧叫Detail。SplitViewController有一个property叫做ViewControllers,它是一个数组,这个数组有两个元素,左侧和右侧,左侧是元素0,右侧是元素1,可以在代码中设置你的两个ViewController(通常得同时设置),可以在xcode中设置这两个东西,可以control拖动到左侧来设置左侧或拖动到右侧来设置右侧,然后它要改变就用segue。

@property (nonatomic, copy) NSArray *viewControllers;

此API不希望你传递含有这两个ViewController的可变数组,然后期待如果你改变了一个,它会以某种方式更新Split View。所以这里说的是我要复制你给我的东西,而且我要使用它。所以如果你要改变它,你得再给我一次。就是不想让你传递可变数组,以防止你改变了它导致发生意外。

Split View不能没有delegate,如果没有设置delegate,那么当Split View进入Portrait模式的时候左侧就会消失,你应该在角落里放一个小按钮,使用户可以点击它来让左侧出现在popover里。这是Split View的工作原理。如果不实现delegate就没办法放上那个按钮,就无法在portrait模式下调出左侧。通常情况下,你要在ViewController的viewDidLoad或awakeFromNib方法里设置此delegate。所以Split View的delegate最主要的任务就是处理旋转,delegate是管理左侧的。

- (BOOL)splitViewController:(UISplitViewController *)sendershouldHideViewController:(UIViewController *)masterinOrientation:(UIInterfaceOrientation)orientation
{return YES; // always hide it
}

这个delegate方法是被发送到你的delegate询问在特定方向下你想要左侧做什么,因此它把自己传递给你,还有左侧,它会问在这个方向你想要我对左侧做什么。要隐藏就返回YES,要保留在屏幕上就返回NO。

- (BOOL)splitViewController:(UISplitViewController *)sendershouldHideViewController:(UIViewController *)masterinOrientation:(UIInterfaceOrientation)orientation
{return UIInterfaceOrientationIsPortrait(orientation);
}

这是如果不实现delegate其余的方法会出现的问题,因为portrait会隐藏左侧,但你没有放那个小按钮,系统不会帮你做这一步。它会给你按钮,但你得把它放到屏幕上。因此,其余的delegate方法就是要把按钮放上去。其中有两个非常重要,一个用来把按钮放上去,一个用来把按钮拿掉。例如旋转回Landscape:

- (void)splitViewController:(UISplitViewController *)senderwillHideViewController:(UIViewController *)masterwithBarButtonItem:(UIBarButtonItem *)barButtonItemforPopoverController:(UIPopoverController *)popover
{barButtonItem.title = @“Master”; // use a better word than “Master”!// setSplitViewBarButtonItem: must put the bar button somewhere on screen// probably in a UIToolbar or a UINavigationBar
     [detailViewController setSplitViewBarButtonItem:barButtonItem];
}

这是用来隐藏左侧的,它给你一个barButton,就是第三个参数,它说把这个barButton放到屏幕上,因为我将要隐藏左侧的ViewController。当这个barButton被按下,它会自动显示左侧,但是必须把barButton放到某处。

当你想要旋转回Landscape,并把左侧放回到屏幕上,它会向你发送此消息:

- (void)splitViewController:(UISplitViewController *)senderwillShowViewController:(UIViewController *)masterinvalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{// removeSplitViewBarButtonItem: must remove the bar button from its toolbar
   [detailViewController removeSplitViewBarButtonItem:nil];
}

这就是把按钮从工具栏里移除,因为不想左侧显示时,还有这个按钮。

有很多办法可以用来实现SplitView delegate,这取决于在两侧使用的是什么ViewController。何时该设置delegate:一、你得决定谁是delegate,是左侧的Master还是右侧detail?此外你得去考虑可重用性,两者之一可能是通用的,所以不能在那上面实现SplitView delegate,它是一个通用的可重复使用的view。这有个例子,在Detail一侧总是把按钮放上去,那么按钮就总是在Detail一侧。

- (void)setSplitViewBarButtonItem:(UIBarButtonItem *)barButtonItem
{UIToolbar *toolbar = [self toolbar]; // might be outlet or calculatedNSMutableArray *toolbarItems = [toolbar.items mutableCopy];if (_splitViewBarButtonItem) [toolbarItems removeObject:_splitViewBarButtonItem];// put the bar button on the left of our existing toolbarif (barButtonItem) [toolbarItems insertObject:barButtonItem atIndex:0];toolbar.items = toolbarItems;_splitViewBarButtonItem = barButtonItem;
}

这个方法会把barButtonItem插入到工具栏的最左侧,不管工具栏里的其他东西它都会被插在左侧。

通常,点击Master里的东西,Detail显示你点击的东西的详细信息。那么当Master改变时,Detail是怎么更新的?有两个选择,一是简单的target action,在左侧的Master View你已经有了一些按钮或什么,当被点击它会发送target action消息给你的Master Controller。当它想更新Detail,它只要发一个消息到Detail。它是如何从Master得到Detail的?例如Master View Controller里一个target action消息叫doit:

- (IBAction)doit
{id detailViewController = [[self.splitViewController viewControllers] lastObject];[detailViewController setSomeProperty:...];
}

二是也可以segue,在SplitViewController里只有一种segue能用,它被称为replace segue,这是因为它会替换Master或Detail。使用replace segue有个要警告的地方:当你替换Detail View的时候,如果工具栏里有SplitView barButton,该工具栏也被替换,因为整个view都会被替换,所以你得把SplitView barButton转移出来,得把它转移到新的delegate生成的popover上,通常在准备segue的时候去完成做这些。所以如果你要准备segue,你需要问detail关于它的barButton,你设置barButton,然后让segue发生。

Popover

就是漂浮选单,它只是一个NSObject,它控制ViewController,它的工作基本上就是通过contentViewController绘制它的ViewController。通常Popover发生内容,是因为你control拖动它,并有一个segue。Popover segue做的是,你control拖动它到ViewController,它会把ViewController放到Popover里,不管是从按钮或什么拖动,那就是Popover的指向。如果你在代码中做Popover,或使用了storyboard,在storyboard的方法instantiateViewControllerWithIdentifier会给你一个storyboard外部的ViewController。如果得到一个ViewController,然后发消息给UIPopoverController,进行alloc/init就有了PopoverController,你向其发送这两个消息之一,使其出现在屏幕上。

- (void)presentPopoverFromRect:(CGRect)aRect orinView:(UIView *)viewpermittedArrowDirections:(UIPopoverArrowDirection)directionanimated:(BOOL)flag;

- (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)barButtonItempermittedArrowDirections:(UIPopoverArrowDirection)directionanimated:(BOOL)flag;

得保持一个strong指针指向你的PopoverController,所有这些显示的东西都不会有strong指针指向你的PopoverController。

消除Popover,把它从屏幕上去掉,通常是用户触发的,有两种方式:一是如果点击了屏幕上除Popover以外的地方,它会关闭Popover;当你点击Popover里的东西,它是怎么消除的呢?答案是调用了dismissPopoverAnimated,但你不能从popover里的ViewController调用dismissPopoverAnimated。不管把Popover放上来的是哪个对象,这个对象就应该负责消除Popover。

Popover有delegate,实际上它有两个方法,一是问你是否要消除,另一个是告诉你它何时被消除,但这只发生在有人通过点击Popover以外的地方来消除的情况。

设置Popover大小的方式:一最常用的方法是在xcode里设置,选中一个ViewController并inspect它,通过Popover小开关打开并指定大小;二是通过UIViewController中的contentSizeForViewInPopover方法;第三种方式是UIPopoverController有个方法可以设置Popover的大小。

Universal Applications

一个通用app就是单一一个应用程序,但可以运行在ipad或iphone上,可以共享ViewController。调用这个宏UI_USER_INTERFACE_IDIOM可以知道在ipad上运行,你问它是UIUserInterfaceIdiomPad还是UIUserInterfaceIdiomPhone,这会告诉你是否在ipad上运行:

BOOL iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);

但这不是最好的办法,询问我是否处在SplitViewController里会更好。

Demo

修改上一节的demo,使其成为一个通用app,其中要创建一个ipad的storyboard。

修改spring&structs,如果视图控制器是UIViewController类,则需要一个UIViewController子类重载shouldAutorotateToInterfaceOrientation方法才能进行旋转。创建完UIViewController的子类后只要留下shouldAutorotateToInterfaceOrientation方法,并使它返回yes。

修改app设置使其成为一个通用app,把原来的MainStoryboard.storyboard改为:iPhone.storyboard,修改iPhone的storyboard:

新建iPad.storyboard,并设置iPad的storyboard。

在iPad.storyboard里拖一个SplitViewController进来,删除tableViewController,修改右侧控制器的类为HappinessViewController,再拖一个View到HappinessViewController并把它的类修改为FaceView,要设置outlet和action。在iPhone.storyboard中复制根视图控制器,到iPad.storyboard再粘贴,从导航控制器control拖动到根视图控制器,再把Psychologist View Controller粘贴过来并用segue关联起来:

修改PsychologistViewController.m中的代码如下:

- (HappinessViewController *)splitViewHappinessViewController
{id hvc = [self.splitViewController.viewControllers lastObject];if (![hvc isKindOfClass:[HappinessViewController class]]) {hvc = nil;}return hvc;
}- (void)setAndShowDiagnosis:(int)diagnosis
{self.diagnosis = diagnosis;if ([self splitViewHappinessViewController]) {[self splitViewHappinessViewController].happiness = diagnosis;}else{[self performSegueWithIdentifier:@"ShowDiagnosis" sender:self];}
}

把SplitView delegate放进RotatableViewController,让RotatableViewController成为SplitView的delegate。RotatableViewController的代码如下:

#import <UIKit/UIKit.h>@interface RotatableViewController : UIViewController<UISplitViewControllerDelegate>@end

#import "RotatableViewController.h"#import "SplitViewBarButtonItemPresenter.h"@implementation RotatableViewController- (void)awakeFromNib{[super awakeFromNib];self.splitViewController.delegate = self;
}- (id <SplitViewBarButtonItemPresenter>)splitViewBarButtonItemPresenter
{id detailVC = [self.splitViewController.viewControllers lastObject];if (![detailVC conformsToProtocol:@protocol(SplitViewBarButtonItemPresenter)]) {detailVC = nil;}return detailVC;
}- (BOOL)splitViewController:(UISplitViewController *)svcshouldHideViewController:(UIViewController *)vcinOrientation:(UIInterfaceOrientation)orientation
{return [self splitViewBarButtonItemPresenter]? UIInterfaceOrientationIsPortrait(orientation) : NO;
}- (void)splitViewController:(UISplitViewController *)svcwillHideViewController:(UIViewController *)aViewControllerwithBarButtonItem:(UIBarButtonItem *)barButtonItemforPopoverController:(UIPopoverController *)pc
{barButtonItem.title = self.title;[self splitViewBarButtonItemPresenter].splitViewBarButtonItem = barButtonItem;
}- (void)splitViewController:(UISplitViewController *)svcwillShowViewController:(UIViewController *)aViewControllerinvalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{[self splitViewBarButtonItemPresenter].splitViewBarButtonItem = nil;
}- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{// Return YES for supported orientationsreturn YES;
}@end

创建一个protocol,代码如下:

#import <UIKit/UIKit.h>@protocol SplitViewBarButtonItemPresenter <NSObject>@property (nonatomic,strong) UIBarButtonItem *splitViewBarButtonItem;@end

HappinessViewController .h文件代码:

#import <UIKit/UIKit.h>
#import "SplitViewBarButtonItemPresenter.h"@interface HappinessViewController : UIViewController<SplitViewBarButtonItemPresenter>@property (nonatomic) int happiness;  // 0 is sad; 100 is very happy@end

HappinessViewController.m实现协议:

#import "HappinessViewController.h"
#import "FaceView.h"@interface HappinessViewController() <FaceViewDataSource>
@property (nonatomic, weak) IBOutlet FaceView *faceView;
@property (nonatomic, weak) IBOutlet UIToolbar *toolbar;
@end@implementation HappinessViewController@synthesize happiness = _happiness;
@synthesize faceView = _faceView;
@synthesize splitViewBarButtonItem = _splitViewBarButtonItem;
@synthesize toolbar = _toolbar;- (void)setSplitViewBarButtonItem:(UIBarButtonItem *)splitViewBarButtonItem
{if (_splitViewBarButtonItem != splitViewBarButtonItem) {NSMutableArray *toolbarItems = [self.toolbar.items mutableCopy];if (_splitViewBarButtonItem) {[toolbarItems removeObject:_splitViewBarButtonItem];}if (splitViewBarButtonItem) {[toolbarItems insertObject: splitViewBarButtonItem atIndex:0 ];}self.toolbar.items = toolbarItems;_splitViewBarButtonItem = splitViewBarButtonItem;}
}
//.......

运行结果如下所示:

iOS应用开发视频教程笔记iPad Apps相关推荐

  1. iOS应用开发视频教程笔记(二)My First iOS App

    这课主要是以一个计算器一个用为例子,教你怎么使用XCode,如何使用MVC设计模式创建应用. (1)新建一个single view application模版的应用 打开xcode并点击"创 ...

  2. iOS 实战开发课程笔记

    iOS 实战开发课程笔记 本贴旨在作为对极客班 <iOS 开发实战>第五期期课程视频重新学习的笔记. 目标是建立一个比较完整的 iOS 开发知识点框架以及快速手册. 对各个内容的详细研究会 ...

  3. Objective-c/iOS/iphone开发视频教程迅雷/高速下载

    转自:http://www.lwxshow.com/videos/objective-c-ios-iphone-development-video-tutorials-download-now-rea ...

  4. 新增迅雷下载地址:Objective-c/iOS/iphone开发视频教程迅雷/高速下载

    转自:http://www.lwxshow.com/archives/397 2012-4-10更新 大家访问 http://www.lwxshow.com/archives/397 看到一个2012 ...

  5. iOS初级开发学习笔记:APP生命周期的学习总结

    我们平常使用APP时,一般人都会知道有:简单的正在使用状态:通过home键等方式离开应用,但是不关闭应用,即后台状态:以及调出后台程序管理后向上滑动将应用"杀死",三种状态.而我们 ...

  6. iOS初级开发学习笔记:微信充值

    相关教程:微信支付开发流程 一直到设置URL Scheme,均按照步骤进行.下面的内容将作为笔记着重介绍: 注册APPID步骤1-3: 在AppDelegate.m中 1.导入#import &quo ...

  7. TMS320C6748开发视频教程笔记 第12章 通用输入输出口 GPIO

    第12章 通用输入输出口 GPIO General-purpose input/output 12-1 相关例程演示 12-2 管脚复用配置 12-3 输入输出模式 12-4 中断 12-5 EDMA ...

  8. TMS320C6748开发视频教程笔记 第7章 启动与烧写

    第7章 启动与烧写 7-1 启动流程及方式 7-2 AIS文件结构 7-3 通过串口加载运行程序 7-4 配置并生成AIS文件 7-5 程序烧写 7-4-1 CCS烧写 7-4-2 串口烧写 7-4- ...

  9. TMS320C6748开发视频教程笔记 第9章 中断与异常

    第9章 中断与异常 9 中断与异常 9-1 中断 9-1-1 中断类型 9-1-2 中断结构 9-1-3 中断事件选择 9-1-4 中断错误事件 9-1-5 中断向量表 9-1-6 中断嵌套 9-2 ...

最新文章

  1. Java学习总结:31(StringBuffer类)
  2. python基础===拆分字符串,和拼接字符串
  3. html5的消息通知
  4. 设置联想电脑双屏显示(备用待查)
  5. Python的魔法函数
  6. 《Android开发精要》读书笔记——Android应用模型
  7. c语言的链表怎么写,写一个C语言的链表记录一下
  8. Spring Boot太难了?那是你不知道这3个要点!
  9. 解决Amlogic S905或S9xxx在安装Armbian_20.02.0卡logo或无反应的方法
  10. thrift (转)
  11. atitit.软件设计模式大的总结attialx总结
  12. 强烈推荐!Python 这个宝藏库 re 正则匹配
  13. 双目视觉测距离(三维重建)
  14. 虚幻引擎4初探(UE4)
  15. Qt编写物联网管理平台13-短信告警
  16. 如何高效地做设计评审
  17. SpringCloud学习笔记3:Spring Cloud Netflix 组件(五大神兽)
  18. 《泰囧》票房奇迹:极简主义的胜利
  19. 胎儿超声标准切面 图与详解
  20. 如何将word自带的公式快速转为latex?

热门文章

  1. 手游8月大维权 中小团队生存压力加大
  2. 考研日语-被动用法的构成与使用
  3. 学计算机大学生买什么牌子电脑,大学生买手提电脑什么牌子好
  4. cmd命令进入mysql数据库_cmd命令怎么打开mysql?
  5. python随机数并输出偶数个数_python随机数的产生
  6. Netty 单机百万连接测试
  7. 500字写一篇决策与判断这本书的读后感
  8. Java8 流式递归树形菜单
  9. 摄像头人数统计解决方案:Camlytics 2.2.8 Crack
  10. 高数 | 【数列】递推型数列 与 极限