转载

使用iOS 8的新特性实现Shutterbug

使用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选择显示模式:

  • UIUserInterfaceSizeClassCompact对应UISplitViewControllerDisplayModePrimaryHidden模式

  • UIUserInterfaceSizeClassRegular对应UISplitViewControllerDisplayModeAllVisible模式

  • 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的子类充当。 程序中我采用的是这种方式。

2)何时设置UISplitViewController的委托

如果你是采用的Storyboard或xib文件,建议在 awakeFromNib 里设置。在查阅资料的时候发现有些人遇到了委托方法没触发的问题。大家都建议尽早的设置委托。

3)当在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,它会采用默认的处理方式处理。

4)在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里已经过时了。经查阅文档,官方推荐在该方法中处理。

5)在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 ,希望对你有帮助。

参考资料

UISplitViewController 和 UISplitViewControllerDelegate

2014 WWDC视频 Building Adaptive Apps with UIKit

NShipster

原文  http://www.cocoachina.com/ios/20160803/17268.html
正文到此结束
Loading...