Reusable button bars?

2019-09-07 10:39发布

问题:

I'm implementing an IOS6 app using storyboards. I want every screen--excuse me, scene--for the app to have a view at the top containing different image buttons of different sizes. Tapping the buttons takes the user to different scenes of the app.

That's too complex for a UITabController, as far as I can tell. I tried making a separate view controller for that view and including the view in each scene, but any functionality in the view--such as the buttons--causes the app to crash.

It looks like I may have to implement this view in the storyboard in one scene, then copy and paste it into every other scene, wiring up the segues from every scene to every other scene. What a maintenance nightmare! Is there a better way?

回答1:

Since you are trying to create a custom UITabBarController, you should use a container view controller. To do that:

  1. Open your storyboard and add a custom UIVIewController (let's call it ContainerViewController).
  2. Insert the UIVIews that represent your tabs into that controller and then insert another UIVIew (*currentView in the code below) that will take the rest of the screen. That's what the child controllers will use to display their scene.
  3. Create a UIVIewController for each scene (child controller) you need, as you would normally, and give each of them a unique identifier (Identity Inspector -> Storyboard ID)

Now you have to add the following code your ContainerViewController:

@interface ContainerViewController ()
    @property (strong, nonatomic) IBOutlet UIView *currentView; // Connect the UIView to this outlet
    @property (strong, nonatomic) UIViewController *currentViewController;
    @property (nonatomic) NSInteger index;
@end

@implementation ContainerViewController

// This is the method that will change the active view controller and the view that is shown
 - (void)changeToControllerWithIndex:(NSInteger)index
{
    if (self.index != index){
        self.index = index;
        [self setupTabForIndex:index];

        // The code below will properly remove the the child view controller that is
        // currently being shown to the user and insert the new child view controller.
        UIViewController *vc = [self setupViewControllerForIndex:index];
        [self addChildViewController:vc];
        [vc didMoveToParentViewController:self];

        if (self.currentViewController){
            [self.currentViewController willMoveToParentViewController:nil];

            [self transitionFromViewController:self.currentViewController toViewController:vc duration:0 options:UIViewAnimationOptionTransitionNone animations:^{
                [self.currentViewController.view removeFromSuperview];
                [self.currentView addSubview:vc.view];
            } completion:^(BOOL finished) {
                [self.currentViewController removeFromParentViewController];
                self.currentViewController = vc;
            }];
        } else {
            [self.currentView addSubview:vc.view];
            self.currentViewController = vc;
        }
    }
}

// This is where you instantiate each child controller and setup anything you need  on them, like delegates and public properties.
- (UIViewController *)setupViewControllerForIndex:(NSInteger)index {

    // Replace UIVIewController with your custom classes
    if (index == 0){
        UIViewController *child = [self.storyboard instantiateViewControllerWithIdentifier:@"STORYBOARD_ID_1"];
        return child;
    } else {
        UIViewController *child = [self.storyboard instantiateViewControllerWithIdentifier:@"STORYBOARD_ID_2"];
        return child;
    }
}

// Use this method to change anything you need on the tabs, like making the active tab a different colour
- (void)setupTabForIndex:(NSInteger)index{

}

// This will recognize taps on the tabs so the change can be done
- (IBAction)tapDetected:(UITapGestureRecognizer *)gestureRecognizer {
    [self changeToControllerWithIndex:gestureRecognizer.view.tag];
}

Finally, each view you create that represents a tab should have it's own TapGestureRecognizer and a number for its tag.

By doing all this you will have a single controller with the buttons you need (they don't have to be reusable), you can add as much functionality you want in them (that's what the setupTabBarForIndex: method will be used) and you won't violate DRY.