Using multiple storyboards with a TabBarController

前端 未结 4 1010
时光说笑
时光说笑 2020-12-09 06:34

Okay, so in the process of developing my newest app, I found that my storyboard got huge, so in an effort to clean it up some, i have divided it into mult

相关标签:
4条回答
  • This is quite possible and a smart move - decluttering your Storyboards presents cleaner interface files to dig through, reduced loading times in XCode, and better group editing.

    I've been combing across Stack Overflow for a while and noticed everyone is resorting to Custom Segues or instantiating tab based setups programmatically. Yikes. I've hacked together a simple UIViewController subclass that you can use as a placeholder for your storyboards.

    Code:

    Header file:

    #import <UIKit/UIKit.h>
    
    @interface TVStoryboardViewController : UIViewController
    
    @end
    

    Implementation file:

    #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
    

    Description:

    1. The view controller uses its Restoration Identifier to instantiate a storyboard in your project.
    2. Once loaded, it will attempt to replace itself in its UINavigationController's viewController array with the Storyboard's initial view controller.
    3. When requested, this subclass will return the UINavigationItem of the Storyboard's initial view controller. This is to ensure that navigation items loaded into UINavigationBars will correspond to the view controllers after the swap.

    Usage:

    To use it, assign it as the subclass of a UIViewController in your Storyboard that belongs to a UINavigationController.

    enter image description here

    Assign it a Restoration ID, and you're good to go.

    enter image description here

    Setup:

    And here's how you set it up in the Storyboard:

    Diagram showing setup

    This setup shows a tab bar controller with navigation controllers as its first tab controllers. Each navigation controller has a simple UIViewController as its root view controller (I've added UIImageViews to the placeholders to make it easy to remember what it links to). Each of them is a subclass of TVStoryboardViewController. Each has a Restoration ID set to the storyboard they should link to.

    Some wins here:

    • It seems to work best for modal presentations where the subclass is the root view controller of a navigation controller.
    • The subclass doesn't push any controllers on the stack - it swaps. This means you don't have to manually hide a back button or override tab behaviour elsewhere.
    • If you double tap on a tab, it will take you to the Storyboard's initial view, as expected (you won't see that placeholder again).
    • Super simple to set up - no custom segues or setting multiple subclasses.
    • You can add UIImageViews and whatever you like to the placeholder view controllers to make your Storyboards clearer - they will never be shown.

    Some limitations:

    • This subclass needs to belong to a UINavigationController somewhere in the chain.
    • This subclass will only instantiate the initial view controller in the Storyboard. If you want to instantiate a view controller further down the chain, you can always split your Storyboards further and reapply this subclass trick.
    • This approach doesn't work well when pushing view controllers.
    • This approach doesn't work well when used as an embedded view controller.
    • Message passing via segues likely won't work. This approach suits setups where sections of interface are unique, unrelated sections (presented modally or via tab bar).

    This approach was hacked up to solve this UITabBarController problem, so use it as a partial solution to a bigger issue. I hope Apple improves on 'multiple storyboard' support. For the UITabBarController setup however, it should work a treat.

    0 讨论(0)
  • 2020-12-09 06:55

    This is a bit late for Hawke_Pilot but it might help others.

    From iOS 9.0 onwards you can create a Relationship Segue to another storyboard. This means that Tab Bar View Controllers can link to View Controllers on another storyboard without some of the mind-bending tricks seen in other answers here. :-)

    However, this alone doesn't help because the recipient in the other storyboard doesn't know it's being linked to a Tab Bar View Controller and won't display the Tab Bar for editing. All you need to do once you point the Storyboard Reference to the required View Controller is select the Storyboard Reference and choose Editor->Embed In->Navigation Controller. This means that the Nav Controller knows it's linked to a Tab Bar View Controller because it's on the same storyboard and will display the Tab Bar at the bottom and allow editing of the button image and title. No code required.

    Admittedly, this may not suit everyone but may work for the OP.

    0 讨论(0)
  • 2020-12-09 06:59

    Add Following code to your 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;
        }
    

    Here is the screenShot for LinkViewController ScreenShot.

    LinkViewController is just a placeholder where new viewController would be placed. Here is the sample code which I used for my app.

    RBStoryboardLink . Its working great for me. Let me know if it is helpful for you.

    0 讨论(0)
  • 2020-12-09 07:10

    Not sure if your question is answered, and for others looking for a solution to this problem, try this method.

    enter image description here

    1. Create the Tab Bar Controller with Navigation Controllers in one storyboard file. And add an empty view controller (I named it RedirectViewController) as shown in the picture.
    2. The child view controller (let's call it SettingsViewController for your case) is located in Settings_iPhone.storyboard.
    3. In RedirectViewController.m, code this:

      - (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 will be pushed into view instantly when Settings tab is touched.
    5. The solution is not complete yet! You will see "< Back" as the left navigationItem on SettingsViewController. Use the following line in its viewDidLoad method:

      self.navigationItem.hidesBackButton = YES;
      
    6. Also, to prevent the same tab bar item from being tap and causes a jump back to the blank rootViewController, the destination view controllers will need to implement UITabBarControllerDelegate

      - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController 
      {
          return viewController != tabBarController.selectedViewController;
      }
      

    It works for me.

    0 讨论(0)
提交回复
热议问题