为我最复杂的 UI 展示故事板...
这就是(目前)六个单独的 UI 选项卡所需要的全部,它们具有无限“深入”视图控制器的多个深度的能力,使用户能够找到他们正在寻找的数据。
警告 警告 警告
我担心用户可能会在这个迷宫中“迷路”。请注意您的 UI 设计,以确保用户了解他们对数据查找 safari 的“深入”程度,或者至少为他们提供一种简单的方法来“弹出”他们的出路。
我将我的 VC/TVC 排列成列以便于使用 - 事实证明 - 便于描述功能。
标签栏控制器和导航控制器是不言自明的。
我将忽略本练习的“特殊功能”控制器。
所以让我们专注于:
- “标准列表”类型的 TVC,
- “详细内容”类型的 TVC,&
- “选择”类型的 TVC。
当用户选择一个选项卡时,“标准列表”类型的 TVC 会提供 UI 以向用户显示项目列表。添加按钮(导航栏项目)提供了通过“详细内容”类型的 TVC 手动将新项目添加到列表的机会。
IB 从“标准列表”转为“详细内容”类型的 TVC
“标准列表”中项目行的故事板(IB 创建)转场触发“详细内容”类型 TVC 的转场,因此用户可以查看和/或编辑项目数据。
“标准列表”中添加按钮(导航栏项)的故事板(IB 创建)转场触发转场到“详细内容”类型 TVC 中的空白或“新”项,因此用户可以添加一个新项目和相关数据。
IB 从“详细内容”转为“选择”类型的 TVC
“详细内容”中项目行的情节提要(IB 创建)转场会触发转场到“选择自”类型 TVC,具体取决于该内容所需的数据类型。 (例如,“Select from”类型的 TVC 之一是嵌入在标准视图控制器中的 UIDatePicker,它使用户能够轻松选择日期和/或时间。)
我想开始从“Select from”类型的 TVC 跳回到“Detail Content”类型的 TVC。
我什至没有尝试手动执行此操作。我的强迫症要求我的情节提要尽可能保持原始和整洁 - NO 疯狂地“倒退”以促进控制器的重用。
所以最后得到一个答案 - 是的,感谢你坚持我 - 我认为序言是必要的。
对于与“Select from”类型 TVC 关联的每个类,我创建了一个自定义 segue,嵌入到 TVC 实现文件的代码中。
随着我对自定义转场越来越熟悉,我可能会将它们删除到单独的“助手”类中。
但在那之前,“Select from”类型TVC的每个类实现文件顶部的代码...
////////////////////////////////////////////////////////////
/// Subclass of UIStoryboardSegue must override -perform ///
////////////////////////////////////////////////////////////
@interface Segue_YourCustomNameHere : UIStoryboardSegue
@end
@implementation Segue_YourCustomNameHere
- (void)perform {
ThisSelectFromClass *sourceViewController = self.sourceViewController;
[sourceViewController.navigationController pushViewController:self.destinationViewController animated:YES];
}
@end
////////////////////////////////////////////////////////////
/// END of subclass of UIStoryboardSegue ///
////////////////////////////////////////////////////////////
@interface ThisSelectFromClass ()
//private declarations
@end
@implementation ThisSelectFromClass
//implementation code
@end
简单,对!
下一步?使用“Storyboard ID”提供您想要重复使用的控制器。
返回您的 Interface Builder / Storyboard 文件,然后选择您想在代码中重用的控制器。
在 Identity Inspector 的“Identity”子标题下,输入“Storyboard ID”。我喜欢在我的故事板 ID 前加上“id_”,如下图示例所示。我将在下面的示例代码中使用此示例,请注意这一点。
下一步?如何触发自定义segue???
回到你的类的实现文件(上面的例子使用ThisSelectFromClass)
让我们建议当用户点击特定的数据行时需要 segue。
代码...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *mainStoryboard = nil;
UIStoryboard *storyboard = nil;
UIViewController *destinationVC = nil;
Segue_YourCustomNameHere *segue = nil;
mainStoryboard = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIMainStoryboardFile"];
storyboard = [UIStoryboard storyboardWithName:mainStoryboard bundle:nil];
// I check the appropriate path depending on the title of my TVC
// You may need to determine another check method.
if ([self.title isEqualToString:<<the title string>>]) {
destinationVC = [storyboard instantiateViewControllerWithIdentifier:@"id_DetailContentVC"];
segue = [[Segue_YourCustomNameHere alloc] initWithIdentifier:@"segue_YourSegueIdentifierNameHere"
source:self
destination:destinationVC];
} else if ([self.title isEqualToString:<<another title string>>]) {
destinationVC = [storyboard instantiateViewControllerWithIdentifier:@"id_NextDetailContentVC"];
segue = [[Segue_YourCustomNameHere alloc] initWithIdentifier:@"segue_YourNextSegueIdentifierNameHere"
source:self
destination:destinationVC];
} else if... // as many iterations as necessary
// Repeat above
} else {
// Do other stuff - maybe error checking?
}
// And because I always incorporate a UISearchDisplayController and I'm too lazy to think about how I should remove it for this example...
id object = nil;
if (tableView == self.tableView) {
object = [self.fetchedResultsController objectAtIndexPath:indexPath];
} else {
object = [self.searchResults objectAtIndex:indexPath.row];
}
// Finally...
[self prepareForSegue:segue sender:object]; // optional
[segue perform];
}
并且,以防万一您需要并在上方添加 // optional 行...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
id segueDestinationVC = segue.destinationViewController;
if ([segue.identifier isEqualToString:@"segue_YourSegueIdentifierNameHere"]) {
// These two lines of code are examples only...
[segueDestinationVC setTitle:[sender valueForKey:@"aSenderKey"]]; // example
[segueDestinationVC setObjectID:[sender objectID]]; // example
} else if ([segue.identifier isEqualToString:@"segue_YourNextSegueIdentifierNameHere"]) {
// These two lines of code are examples only...
[segueDestinationVC setTitle:[sender valueForKey:@"aSenderKey"]]; // example
[segueDestinationVC setObjectID:[sender objectID]]; // example
} else {
// Do other stuff - again maybe error checking?
}
希望这会有所帮助。