在任何 UIViewControllers 之间交替?
Posted
技术标签:
【中文标题】在任何 UIViewControllers 之间交替?【英文标题】:Alternate between ANY UIViewControllers? 【发布时间】:2013-01-20 06:39:13 【问题描述】:这个问题很长,请耐心等待。
我们知道有两种显示控制器的方法:推送或呈现。还有两个复合控制器:tabbarcontroller 和导航控制器。有了这些可以制作复杂的视图控制器树。 现在我有一个像这样的复杂视图控制器树。
T: 标签栏控制器 N:导航控制器 V:普通视图控制器 P:推 S:在场
所以PV2就是push一个viewcontroller,这是六种组合,但是禁止PN,不能push一个navigation controller。在我研究的时候
T1 --------------------- N1 N2 N3 | | PV1 PV3 | PV2现在当前的视图控制器是 V2。我想跳到N3并推V3。 我写了这段代码:
[self.navigationcontroller popToRootViewControllerAnimated:NO]; // No is important
tabbarcontroller.selectIndex = 2;
[N3 pushViewController:V3];
它有效,但仍然很糟糕,太糟糕了。 1:N3必须知道v3,viewcontroller之间的耦合性很强。 2:不能在复杂的情况下工作……也会导致动画问题。
我的一个朋友告诉我,他们制作了一个 PageConductor,可以轻松地在任何视图控制器之间切换。 这真的让我很困惑......
【问题讨论】:
【参考方案1】:N3 知道 V3 有什么问题?您是说 V2 知道 V3 吗?无论如何,我在了解 T 的 V2 中看到了一个更大的问题。如果您真的必须执行此复杂的屏幕流程,请将其委托给专用对象(例如您朋友提到的 PageConductor)。根据用户操作而不是控制器操作(如[screens showUserProfile:userId]
或其他东西)与此对象交谈,这将为您提供控制器之间的真正解耦。
有哪些“复杂情况”示例?至于这种特殊情况下的动画问题,请在弹出 T1 堆栈之前尝试切换到 T3。
更新
一个虚构的应用程序的屏幕管理器的小人为示例。
@implementation ScreenManager
@synthesize tabController = _tabController;
- (BOOL)goToUserList
// user list is a root controller of tab 0 navigation controller
BOOL switched = [self switchToTab:0];
UINavigationController *nc = [self rootNavigationAtTab:0];
[nc popToRootViewControllerAnimated:!switched]; // we should animate popping if we didn't change tabs
return switched;
- (BOOL)showUserProfile:(NSUInteger)userId
BOOL switched = [self goToUserList];
UIViewController *uc = [[UserDetailsController alloc] initWithUserId:userId];
UINavigationController *nc = [self rootNavigationAtTab:0];
[nc pushViewController:uc animated:YES];
return switched;
- (BOOL)showMapAtLocation:(CLLocation *)location
MapController *mc = [self downcast:[self rootControllerAtTab:1] to:[MapController class]];
mc.location = location;
return [self switchToTab:1];
/* returns if we actually switched tabs as a result of this action */
- (BOOL)switchToTab:(NSUInteger)tabIdx
NSUInteger prevTabIdx = _tabController.selectedIndex;
_tabController.selectedIndex = tabIdx;
return prevTabIdx != tabIdx;
- (BOOL)pushController:(UIViewController *)controller animated:(BOOL)animated toTab:(NSUInteger)tabIdx
BOOL switchedTabs = [self switchToTab:tabIdx];
UINavigationController *nc = [self rootNavigationAtTab:tabIdx];
[nc pushViewController:controller animated:animated];
return switchedTabs;
- (UINavigationController *)rootNavigationAtTab:(NSUInteger)tabIdx
return [self downcast:[self rootControllerAtTab:tabIdx] to:[UIViewController class]];
- (id)downcast:(id)obj to:(Class)klass
return [obj isKindOfClass:klass] ? obj : nil;
- (UINavigationController *)rootControllerAtTab:(NSUInteger)tabIdx
return [_tabController.viewControllers objectAtIndex:tabIdx];
+ (ScreenManager *)currentManager
static ScreenManager *manager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
manager = [ScreenManager new];
);
return manager;
@end
这里我们有 3 个操作可供用户使用 - “按 ID 显示用户个人资料”、“显示用户列表”和“在地图上显示某个位置”。人们可能会调整这个基本解决方案以满足他们的应用程序需求,但它的想法是将标签/屏幕管理逻辑与本地控制器逻辑分离。所有操作都返回一个布尔值,指示在此期间是否切换了选项卡,因此客户端代码可以根据此进行一些调整(例如在选项卡更改时弹出其导航堆栈)。
【讨论】:
1.我在N3.m中导入V3只是为了一句话;我使用通知来解耦,所以 V2 不知道 T,pageConductor 是最好的解决方案,但我不知道如何实现它(就像你说的[screens showUserProfile:userId]
)。 2.复杂情况的例子是V3出现了一个tabbarcontroller T2,我想跳到V3。它会导致很多动画问题,引用:“至于这种特殊情况下的动画问题,请在弹出 T1 堆栈之前尝试切换到 T3。”这不是一个常见的解决方案。
抱歉这么久才回复,工作比较忙。 1. N3是导航,你实现自己的导航控制器吗?无论如何,这不是行数问题,而是应用程序语义问题。 2. 我不确定我是否在关注您:V3 出现在选项卡 2 上,您想切换到它吗?这里有什么复杂的?至于页面指挥 - 请参阅更新。以上是关于在任何 UIViewControllers 之间交替?的主要内容,如果未能解决你的问题,请参考以下文章
在 UISplitViewController 和 UIViewControllers 之间导航 [重复]
UIScrollview 中的两个 UIviewControllers - 如何在它们之间调用方法
在两个 UiViewControllers 和 UIViews 之间实现拖动和滑动转换? [关闭]