首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》22.1 在Nerdfeed中使用UISplitViewController

关灯直达底部

前面已介绍过UINavigationController和UITabBarController。和这些视图控制器类似,当初始化UISplitViewController时,也需要传入一组视图控制器。不同的是,UISplitViewController对象只能包含两个视图控制器:一个主视图控制器和一个从视图控制器。某个视图控制器是主还是从,是由该对象在数组中的位置决定的。数组中的第一项是主视图控制器,第二项是从视图控制器。

用Xcode打开Nerdfeed.xcodeproj,然后在项目导航面板中选中BNRAppDelegate.m。

更新application:didFinishLaunchingWithOptions:,检查当前运行的设备是否是iPad,是就创建UISplitViewController对象。iPhone不支持UISplitViewController,如果当前的设备是iPhone,创建UISplitViewController对象则会导致应用抛出异常。代码如下:

- (BOOL)application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

self.window

= [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

BNRCoursesViewController *lvc = [[BNRCoursesViewController alloc]

initWithStyle:UITableViewStylePlain];

UINavigationController *masterNav =

[[UINavigationController alloc] initWithRootViewController:lvc];

BNRWebViewController *wvc = [[BNRWebViewController alloc] init];

lvc.webViewController = wvc;

self.window.rootViewController = masterNav;

// 检查当前设备是否是iPad

if ([[UIDevice currentDevice] userInterfaceIdiom] ==

UIUserInterfaceIdiomPad) {

// 必须将webViewController包含在导航视图控制器中,稍后会解释原因

UINavigationController *detailNav =

[[UINavigationController alloc] initWithRootViewController:wvc];

UISplitViewController *svc = [[UISplitViewController alloc] init];

// 将从视图控制器设置为UISplitViewController对象的委托对象

// 稍后会用到(暂时忽略Xcode对这行代码发出的警告信息)

svc.delegate = wvc;

svc.viewControllers = @[masterNav, detailNav];

// 将UISplitViewController对象设置为UIWindow对象的根视图控制器

self.window.rootViewController = svc;

} else {

// 对于非iPad设备,仍然使用导航视图控制器

self.window.rootViewController = masterNav;

}

self.window.backgroundColor = [UIColor whiteColor];

[self.window makeKeyAndVisible];

return YES;

}

这段代码将创建UISplitViewController对象的代码放入了if子句,这是为将Nerdfeed修改为通用应用做准备。基于同样的原因,读者现在应该明白为什么要在UIApplication的委托中创建BNRWebViewController对象,而不是使用常见的模式(由UINavigationController对象的当前视图控制器创建下一个需要压入UINavigationController栈的对象)。创建UISplitViewController对象时,必需设置主、从视图控制器,缺一不可。图22-2显示的是Nerdfeed的UISplitViewController对象图。

图22-2 UISplitViewController对象图

构建并运行应用,如果设备处于竖排模式,应用界面将没有任何内容;将设备旋转至横排模式,就可以在屏幕上看到两个视图控制器。下一节就会解决这个问题,让Nerdfeed在任何方向都可以正确显示。

如果现在按下UITableView对象中的某个表格行,Nerdfeed并不会在右侧面板(从面板)处显示BNRWebViewController对象,而是会将BNRWebViewController对象压入位于左侧面板(主面板)的UINavigationController栈,以替换掉BNRCoursesViewController对象。要解决该问题,需要在用户按下某个表格行时,检查BNRCoursesViewController对象是否属于某个UISplitViewController对象。如果是,就要执行不同的逻辑。

向某个UIViewController对象发送splitViewController消息,可以得到一个指针,并指向该对象所属的UISplitViewController对象。如果UIViewController对象不属于任何UISplitViewController对象,那么splitViewController方法会返回nil(见图22-3)。实际情况要稍微复杂一点,如果某个视图控制器A是某个UISplitViewController对象B的主/从对象之一,对象A的splitViewController方法就会返回对象B。如果某个视图控制器C不是对象B的主/从对象之一,但是对象A包含对象C,那么对象C的splitViewController方法也会返回对象B(本章的BNRCoursesViewController和BNRWebViewController都属于后一种情况)。

图22-3 UIViewController的splitViewController属性

更新BNRCoursesViewController.m中的tableView:didSelectRowAtIndexPath:,在该方法顶部,在将BNRWebViewController对象压入UINavigationController栈前,检查当前的BNRCoursesViewController对象是否属于某个UISplitViewController对象。代码如下:

- (void)tableView:(UITableView *)tableView

didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

NSDictionary *course = self.courses[indexPath.row];

NSURL *URL = [NSURL URLWithString:course[@“url”]];

self.webViewController.title = course[@“title”];

self.webViewController.URL = URL;

[self.navigationController pushViewController:self.webViewController

animated:YES];

if (!self.splitViewController) {

[self.navigationController pushViewController:self.webViewController

animated:YES];

}

}

如果BNRCoursesViewController对象不属于任何UISplitViewController对象,就可以认为当前的设备不是iPad,应该将BNRWebViewController对象压入UINavigation- Controller栈。如果BNRCoursesViewController对象属于某个UISplitViewController对象,就应该由这个UISplitViewController对象负责显示BNRWebViewController对象。

构建并运行应用,转动设备至横屏模式,按下UITableView对象中的某个表格行,Nerdfeed应该会在右侧面板载入相应的课程页面。