这个问题很长,请耐心等待。
众所周知,有两种显示 Controller 的方法:推送或呈现。还有两个复合 Controller :选项卡 Controller 和导航 Controller 。用这些可以制作复杂的 View Controller 树。 现在我有一个像这样的复杂的 View Controller 树。
T:标签栏 Controller N:导航 Controller V:普通 View Controller 普:推 S:现在
所以PV2的意思是推送一个 View Controller ,这是六种组合,但是PN是被禁止的,你不能推送一个导航 Controller 。当我研究时
T1 --------------------- N1 N2 N3 | | PV1 PV3 | PV2
now the current view controller is V2. i wanna to jump to N3 and push a V3. i wrote this code:
[self.navigationcontroller popToRootViewControllerAnimated:NO]; // No is important
tabbarcontroller.selectIndex = 2;
[N3 pushViewController:V3];
它可以工作,但仍然很糟糕,太糟糕了。 1:N3必须知道v3,viewcontroller之间的耦合性很强。 2:它无法在复杂的情况下工作......还会导致动画问题。
我的一个 friend 告诉我,他们制作了一个 PageConductor,可以轻松地在任何 View Controller 之间切换。 这真的让我很困惑......
最佳答案
N3 知道 V3 有什么问题吗?你的意思是 V2 知道 V3 吗?无论如何,我在了解 T 的 V2 中发现了一个更大的问题。如果您确实必须执行此复杂的屏幕流程,请将其委托(delegate)给专用对象(例如您 friend 提到的 PageConductor)。根据用户操作而不是 Controller 操作(例如
[screens showUserProfile:userId]
或其他)来与此对象交谈,这将为您提供 Controller 之间真正的解耦。“复杂情况”的示例是什么?至于这种特殊情况下的动画问题,请尝试在弹出 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 显示用户个人资料”、“显示用户列表”和“在 map 上显示某个位置”。人们可以调整这一基本解决方案以满足他们的应用程序需求,但其想法是将选项卡/屏幕管理逻辑与本地 Controller 逻辑分离。所有操作都会返回一个 bool 值,指示在此过程中是否切换了选项卡,以便客户端代码可以根据此进行一些调整(例如在选项卡更改时弹出其导航堆栈)。
关于ios - 在任何 UIViewController 之间交替?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14422315/