在任何UIViewControllers之间交替?

时间:2013-01-20 06:39:13

标签: ios uiviewcontroller

这个问题很长,请耐心等待。

我们知道有两种显示控制器的方法:推送或呈现。还有两个复合控制器:tabbarcontroller&导航控制器。用这些可以制作复杂的viewcontrollers树。 现在我有一个像这样的复杂的viewcontroller树。

T:tabbarcontroller N:navigationcontroller V:普通的viewcontroller P:推 S:现在

所以PV2意味着推送一个viewcontroller,这是六种组合,但是PN是禁止的,你不能推动导航控制器。并且正如我研究

  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,viewcontrollers之间的耦合很强。 2:它不能在复杂的情况下工作......也会引起动画问题。

我的一位朋友告诉我他们制作了一个PageConductor,可以轻松地在任何一个视图控制器之间切换。 那让我很困惑......

1 个答案:

答案 0 :(得分:1)

  1. N3知道V3有什么问题?你的意思是V2了解V3吗?无论如何,我在V2中看到一个更大的问题,知道T。如果你真的必须这样做,那么复杂的屏幕流程会将它委托给一个专用对象(比如你朋友提到的PageConductor)。根据用户操作而不是控制器操作(如[screens showUserProfile:userId]或其他东西)来讨论此对象,这将使您在控制器之间实现真正的分离。

  2. 什么是“复杂情况”的例子?至于这种特殊情况下的动画问题,尝试在弹出T1堆栈之前切换到T3。

  3. 更新

    一个想象中的应用程序的屏幕管理器的一个小型人为例子。

    @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显示用户个人资料”,“显示用户列表”和“在地图上显示某个位置”。人们可以调整这个基本的解决方案,以满足他们的应用程序要求,但想法将选项卡/屏幕管理逻辑与本地控制器逻辑分离。所有操作都返回一个布尔值,指示选项卡是否在其中切换,因此客户端代码可以根据此进行一些调整(例如在更改的情况下弹出其导航堆栈)。