使用iOS 8的新特性实现Shutterbug

引言

Shutterbug是斯坦福大学的Paul Hegarty教授在iOS 7开发教学视频中给出的一个示例。Shutterbug访问Flickr的最新图片列表,并显示具体的图片,同时支持iPhone和iPad。具体地参见网易视频 表格视图和iPad

视频中Hegarty教授使用Xcode 6进行代码演示,为了支持iPhone和iPad同时建立了两套Storyboard,即Universal App。在看这个视频的时候,我装的是Xcode 7。Xcode 7支持在一套Storyboard中创建Universal App,这主要是得益于 Size ClassesAuto Layout 特性,具体的可以看下2014 WWDC视频Building Adaptive Apps with UIKit。并且从iOS 8后UISplitViewController可以同时在iPhone和iPad中使用。因此,我想用新的特性去实现这个例子。当然,期间遇到了不少问题,走了不少弯路。在此,我将我遇到的问题分享给大家,以避免犯同样的错误。

UISplitViewController和UISplitViewControllerDelegate

官方给出的UISplitViewController的介绍

The UISplitViewController class is a container view controller that presents a master-detail interface. In a master-detail interface, changes in the primary view controller (the master) drive changes in a secondary view controller (the detail). The two view controllers can be arranged so that they are side-by-side, so that only one at a time is visible, or so that one only partially hides the other. In iOS 8 and later, you can use the UISplitViewController class on all iOS devices; in previous versions of iOS, the class is available only on iPad.

它包含两个视图控制器,一个是主视图控制器,另一个是详细视图控制器。共有三种显示模式:

  1. UISplitViewControllerDisplayModePrimaryHidden
    The primary view controller is hidden.
  2. UISplitViewControllerDisplayModeAllVisible
    The primary and secondary view controllers are displayed side-by-side onscreen.
  3. UISplitViewControllerDisplayModePrimaryOverlay
    The primary view controller is layered on top of the secondary view controller, leaving the secondary view controller partially visible.

还有一种叫 UISplitViewControllerDisplayModeAutomatic,其实就是让UISplitViewController根据当前的Size Classes选择上述的三种显示模式。真正的显示模式应该只有三种。在 UISplitViewControllerDisplayModeAutomatic 模式下,UISplitViewController会根据水平方向的size class选择显示模式:

  1. UIUserInterfaceSizeClassCompact对应UISplitViewControllerDisplayModePrimaryHidden模式
  2. UIUserInterfaceSizeClassRegular对应UISplitViewControllerDisplayModeAllVisible模式
  3. UISplitViewControllerDisplayModePrimaryOverlay对应UISplitViewControllerDisplayModePrimaryHidden模式时以Popover形式显示主视图。

具体的可以参考 官方文档或者看下NShipster中的 这篇文章

UISplitViewControllerDelegate 的帮助文档参见 苹果文档。这里我介绍下程序中用到的两个委托方法。

-(BOOL)splitViewController:(UISplitViewController *)splitViewController
collapseSecondaryViewController:(UIViewController *)secondaryViewController
 ontoPrimaryViewController:(UIViewController *)primaryViewController
 -(void)splitViewController:(UISplitViewController *)svc
   willChangeToDisplayMode:(UISplitViewControllerDisplayMode)displayMode

第一个方法当详细视图折叠到主视图时调用,也就是对应的UISplitViewControllerDisplayModePrimaryHidden模式。第二个方法当显示模式发生变化时调用。下面结合着程序中遇到的问题,介绍下这两个方法的使用。

遇到的问题及解决方法

  1. 由谁来充当委托对象
    我查了些资料,这个没有定论,得结合自己的实际情况。
  • Building Adaptive Apps with UIKit这个视频给出的例子中,由程序委托充当委托。
  • 详细视图控制器充当委托。这种情况,我在Stackoverflow上看到的比较多。
  • 通过扩展。NShipster中的 这篇文章就是这种方式。
  • 由UISplitViewController的子类充当。程序中我采用的是这种方式。
  1. 何时设置UISplitViewController的委托
    如果你是采用的Storyboard或xib文件,建议在 awakeFromNib 里设置。在查阅资料的时候发现有些人遇到了委托方法没触发的问题。大家都建议尽早的设置委托。

  2. 当在iPhone上竖屏显示时,详细视图默认Push到了主视图之上
    解决这个问题可以用以下代码:

-(BOOL)splitViewController:(UISplitViewController *)splitViewController
collapseSecondaryViewController:(UIViewController *)secondaryViewController
 ontoPrimaryViewController:(UIViewController *)primaryViewController
{
    if ([secondaryViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController *nav = (UINavigationController *)secondaryViewController;
        if ([nav.topViewController isKindOfClass:[ImageViewController class]]) {
            ImageViewController *controller = (ImageViewController *)nav.topViewController;
            if (!controller.imageURL) {
                return YES;
            }
        }
    }
    return NO;
}

该方法返回一个BOOL值,如果返回YES表示由我们自己处理,反之交给UISplitViewController,它会采用默认的处理方式处理。

  1. 在iPad里,由横屏切换为竖屏时,详细视图左侧没有barButtonItem
    解决这个问题可以用以下代码:
-(void)splitViewController:(UISplitViewController *)svc
   willChangeToDisplayMode:(UISplitViewControllerDisplayMode)displayMode
{
    UIViewController *primaryViewController = svc.viewControllers[0];
    UIViewController *secondaryViewController = svc.viewControllers[1];

    if ([secondaryViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController *nav = (UINavigationController *)secondaryViewController;
        if ([nav.topViewController isKindOfClass:[ImageViewController class]]) {
            ImageViewController *controller = (ImageViewController *)nav.topViewController;
            controller.navigationItem.leftBarButtonItem=self.displayModeButtonItem;
            controller.navigationItem.leftBarButtonItem.title=((UINavigationController *)primaryViewController).topViewController.title;
            controller.navigationItem.leftItemsSupplementBackButton = true;
        }
    }
}

UISplitViewController没有给出获取主和详细视图控制器的快捷属性。在本程序中,viewControllers中的第一个就是主视图控制器,第二个是详细视图控制器,并且与显示模式无关。
另外,我发现在iOS 7的时代,有几个其他委托也可以实现这种操作,但是在iOS 8里已经过时了。经查阅文档,官方推荐在该方法中处理。

  1. 在iPad竖屏时,初次进入App,详细视图左侧没有barButtonItem
    这个问题可以通过初次初始化ImageViewController时设置leftBarButtonItem来解决:
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self.scrollView addSubview:self.imageView];
    [self startDownloadingImage];
    if(self.traitCollection.userInterfaceIdiom==UIUserInterfaceIdiomPad)
    {
        self.navigationItem.leftBarButtonItem=self.splitViewController.displayModeButtonItem;
    }
}

注意 这里加了个判断,只有在iPad里才生效。如果不加判断,iPhone里初次显示详细视图时会有问题。

总结

之前很少用到UISplitViewController,发现有些东西刚开始还是有些不易理解。尤其结合着Size Class特性。遇到问题还是应该多看下官方文档、WWDC相关视频及Stackoverflow。代码我已经上传到Github,希望对你有帮助。

参考资料

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

推荐阅读更多精彩内容

  • 更好的阅读体验,请到个人博客阅读: iOS中的系统转场 请忽略标题,😂,本文记录的是对下图所示的Kind, Pre...
    CaryaLiu阅读 2,338评论 0 1
  • 就在刚才,突然灵机一动。在身边人的刺激之下,买了一把尤克里里,其实本身是想学吉他的,想到父亲年轻时,也是一位背着...
    无忧亦无惧阅读 152评论 0 1
  • 飞羽是一个才华横溢的女孩子,从小便被称为才女,看书写文章是她的爱好,一有空闲便投身于文字的海洋,她说文字的世界仿佛...
    小淑爱酷仔阅读 299评论 0 1
  • 一个人来到遥远又陌生的城市,开着窗,看着狂轰滥炸的雨,等这城市的华灯初上… 我,就这样一直静静地站着,盼望着雨能快...
    东归小练阅读 821评论 0 2
  • 今天看了一篇文章,分享给大家 故事 李嘉诚的女秘书跟李嘉诚工作了20多年,准备辞职离去。李嘉诚看她兢兢业业干了这么...
    755b978ee8ff阅读 245评论 0 1