使用带有TabBarController的多个故事板

时间:2014-01-06 05:57:44

标签: ios iphone objective-c storyboard uitabbarcontroller

好的,所以在开发我的最新应用程序的过程中,我发现我的storyboard变大了,所以为了清理它,我把它分成multiple storyboards才得到它失控。仅仅针对设置我大约有20 tableviewcontrollers从根NavigationController分支出来。那个navigationcontrollerTabBarController上的一个TabItem,它是application's根视图控制器。

我已将TabBar移动到它自己的StoryBoard作为Root_Storyboard,导航控制器现在是Settings_Storyboard的初始视图。

出于测试目的,我在UIViewControllers(Root_Storyboard)和子类中添加了一些TabBarController作为标签项,并将以下代码添加到viewWillAppear方法中。它效果很好,但我知道presentViewController以模态方式显示NavigationController并隐藏tabBar。显然我不希望如此,如何让它正确推送以便TabBar仍然可见?

- (void) viewWillAppear:(BOOL)animated {
UIStoryboard *settingsStoryboard = [UIStoryboard storyboardWithName:@"Settings_iPhone" bundle:nil];
UIViewController *rootSettingsView = [settingsStoryboard instantiateInitialViewController];

[self.tabBarController presentViewController:rootSettingsView animated:NO completion:NULL];
}

编辑 - 澄清。上面的代码是Root_iPhone.storyboard中UIViewController (child of UITabBarController:index(1))的子类方法。我尝试加载的UINavigationController/UITableViewController位于Settings_iPhone.storyboard。在这种情况下,不确定如何实现下面建议的linkView。

4 个答案:

答案 0 :(得分:10)

这是非常可能的,并且是一个聪明的举动 - 整理你的故事板提供了更清晰的界面文件,可以深入挖掘,减少XCode的加载时间,以及更好的组编辑。

我一直在梳理Stack Overflow一段时间,并注意到每个人都采用自定义分段或以编程方式实例化基于选项卡的设置。让人惊讶。我已经破解了一个简单的UIViewController子类,您可以将其用作故事板的占位符。

<强>代码:

标题文件:

#import <UIKit/UIKit.h>

@interface TVStoryboardViewController : UIViewController

@end

实施文件:

#import "TVStoryboardViewController.h"



@interface TVStoryboardViewController()

@property (nonatomic, strong) UIViewController *storyboardViewController;

@end



@implementation TVStoryboardViewController



- (Class)class { return [self.storyboardViewController class]; }

- (UIViewController *)storyboardViewController
{
    if(_storyboardViewController == nil)
    {

        UIStoryboard *storyboard = nil;
        NSString *identifier = self.restorationIdentifier;

        if(identifier)
        {
            @try {
                storyboard = [UIStoryboard storyboardWithName:identifier bundle:nil];
            }
            @catch (NSException *exception) {
                NSLog(@"Exception (%@): Unable to load the Storyboard titled '%@'.", exception, identifier);
            }
        }

        _storyboardViewController = [storyboard instantiateInitialViewController];
    }

    return _storyboardViewController;
}

- (UINavigationItem *)navigationItem
{
    return self.storyboardViewController.navigationItem ?: [super navigationItem];
}

- (void)loadView
{
    [super loadView];

    if(self.storyboardViewController && self.navigationController)
    {
        NSInteger index = [self.navigationController.viewControllers indexOfObject:self];

        if(index != NSNotFound)
        {
            NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
            [viewControllers replaceObjectAtIndex:index withObject:self.storyboardViewController];
            [self.navigationController setViewControllers:viewControllers animated:NO];
        }
    }
}

- (UIView *)view { return self.storyboardViewController.view; }



@end

说明

  1. 视图控制器使用其恢复标识符来实例化项目中的故事板。
  2. 一旦加载,它将尝试在其中替换自己 UINavigationController的viewController数组与Storyboard的 初始视图控制器。
  3. 当请求时,此子类将返回Storyboard的初始视图控制器的UINavigationItem。这是为了确保加载到UINavigationBars中的导航项与交换后的视图控制器相对应。
  4. <强>用法:

    要使用它,请将它指定为属于UINavigationController的Storyboard中的UIViewController的子类。

    enter image description here

    为它分配一个恢复ID,你很高兴。

    enter image description here

    <强>设定:

    以下是您在故事板中设置的方式:

    Diagram showing setup

    此设置显示一个标签栏控制器,其中导航控制器作为其第一个标签控制器。每个导航控制器都有一个简单的UIViewController作为其根视图控制器(我已经将UIImageViews添加到占位符中,以便于记住它链接到的内容)。它们中的每一个都是TVStoryboardViewController的子类。每个都有一个恢复ID设置为他们应链接到的故事板。

    有些胜利:

    • 它似乎最适用于模式演示,其中子类是导航控制器的根视图控制器。
    • 子类不会推送堆栈上的任何控制器 - 它交换。这意味着您不必手动隐藏后退按钮或覆盖其他位置的选项卡行为。
    • 如果您双击选项卡,它将按照预期将您带到Storyboard的初始视图(您将不会再看到该占位符)。
    • 设置起来非常简单 - 没有自定义segues或设置多个子类。
    • 您可以将UIImageViews和您喜欢的任何内容添加到占位符视图控制器中,以使您的故事板更清晰 - 它们永远不会显示。

    一些限制:

    • 此子类需要属于链中某处的UINavigationController。
    • 此子类仅实例化Storyboard中的初始视图控制器。如果你想在链中进一步实例化一个视图控制器,你可以随时拆分你的故事板并重新应用这个子类技巧。
    • 推送视图控制器时,此方法无法正常工作。
    • 当用作嵌入式视图控制器时,此方法无法正常工作。
    • 通过segue传递的消息可能无法正常工作。这种方法适合于界面部分是唯一的,不相关的部分(以模态方式或通过标签栏显示)的设置。

    这种方法被黑客攻击以解决此UITabBarController问题,因此将其用作更大问题的部分解决方案。我希望Apple能够改进“多故事板”支持。但是对于UITabBarController设置,它应该可以处理。

答案 1 :(得分:6)

对于Hawke_Pilot来说这有点晚了,但它可能对其他人有所帮助。

从iOS 9.0开始,您可以为另一个故事板创建关系搜索。这意味着标签栏视图控制器可以链接到另一个故事板上的视图控制器,而不会在其他答案中看到一些令人费解的技巧。 : - )

但是,仅此一项并没有帮助,因为其他故事板中的收件人不知道它被链接到标签栏视图控制器,并且不会显示标签栏进行编辑。将Storyboard参考指向所需的View Controller后,您只需选择Storyboard Reference并选择Editor-&gt; Embed In-&gt; Navigation Controller。这意味着导航控制器知道它链接到标签栏视图控制器,因为它位于同一个故事板上,并将在底部显示标签栏并允许编辑按钮图像和标题。无需代码。

不可否认,这可能不适合所有人,但可能会为OP工作。

答案 2 :(得分:5)

不确定您的问题是否得到了解答,并且对于寻找此问题解决方案的其他人,请尝试使用此方法。

enter image description here

  1. 在一个故事板文件中使用导航控制器创建标签栏控制器。并添加一个空视图控制器(我将其命名为RedirectViewController),如图所示。
  2. 子视图控制器(我们称之为SettingsViewController为您的案例)位于Settings_iPhone.storyboard。
  3. 在RedirectViewController.m中,代码为:

    - (void)viewWillAppear:(BOOL)animated 
    {
        UIStoryboard *settingsStoryboard = [UIStoryboard storyboardWithName:@"Settings_iPhone" bundle:nil];
        UIViewController *rootSettingsView = [settingsStoryboard instantiateInitialViewController];
    
        [self.navigationController pushViewController:rootSettingsView animated:NO completion:nil];
    }
    
  4. 触摸设置标签时,SettingsViewController将立即进入视图。
  5. 解决方案尚未完成!您将在SettingsViewController上看到“&lt; Back”作为左侧navigationItem。在viewDidLoad方法中使用以下行:

    self.navigationItem.hidesBackButton = YES;
    
  6. 此外,为了防止同一个标签栏项被点击并导致跳回到空白的rootViewController,目标视图控制器将需要实现UITabBarControllerDelegate

    - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController 
    {
        return viewController != tabBarController.selectedViewController;
    }
    
  7. 它对我有用。

答案 3 :(得分:2)

将以下代码添加到LinkViewController

-(void) awakeFromNib{
    [super awakeFromNib];
    ///…your custom code here ..

    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:self.storyBoardName bundle:nil];
    UIViewController * scene = nil;

    // Creates the linked scene.
    if ([self.sceneIdentifier length] == 0)
        scene = [storyboard instantiateInitialViewController];
    else
        scene = [storyboard instantiateViewControllerWithIdentifier:self.sceneIdentifier];
        if (self.tabBarController)
            scene.tabBarItem = self.tabBarItem;
    }

这是LinkViewController ScreenShot的screenShot。

LinkViewController只是一个占位符,可以放置新的viewController。这是我用于我的应用程序的示例代码。

RBStoryboardLink。它对我很有用。如果它对您有帮助,请告诉我。