Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
225 views
in Technique[技术] by (71.8m points)

ios - Changing view controller when Segmented Control changes

This problem is driving me crazy. I'm trying to change the viewController when the user changes the selected "tab" of the segmented control. I've spent a couple hours researching and haven't been able to find an answer that works or is done through storyboard.

It really bother me since setting a tab application is so easy, but trying to use the segmented control like the tab application is just not working. I already know how to detect which index is selected in the segmented control. How can I achieve this?

Thank you very much.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

NOTE: Answer updated with view controller containment code for iOS 5+ including @interface section

In an app of mine, I have a view controller with a Segment Control in the Navigation Bar and clicking on the "tabs" switches view controllers. The basic idea is to have an array of view controllers and switch between them using the Segment Index (and the indexDidChangeForSegmentedControl IBAction.

Example code (iOS 5 or later) from my app (this is for 2 view controllers but it's trivially extended to multiple view controllers); the code is slightly longer than for iOS 4 but will keep the object graph intact. Also, it uses ARC:

@interface MyViewController ()
// Segmented control to switch view controllers
@property (weak, nonatomic) IBOutlet UISegmentedControl *switchViewControllers;

// Array of view controllers to switch between
@property (nonatomic, copy) NSArray *allViewControllers;

// Currently selected view controller
@property (nonatomic, strong) UIViewController *currentViewController;
@end

@implementation UpdateScoreViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    // Create the score view controller
    ViewControllerA *vcA = [self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerA"];

    // Create the penalty view controller
    ViewControllerB *vcB = [self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerB"];

    // Add A and B view controllers to the array
    self.allViewControllers = [[NSArray alloc] initWithObjects:vcA, vcB, nil];

    // Ensure a view controller is loaded
    self.switchViewControllers.selectedSegmentIndex = 0;
    [self cycleFromViewController:self.currentViewController toViewController:[self.allViewControllers objectAtIndex:self.switchViewControllers.selectedSegmentIndex]];
}

#pragma mark - View controller switching and saving

- (void)cycleFromViewController:(UIViewController*)oldVC toViewController:(UIViewController*)newVC {

    // Do nothing if we are attempting to swap to the same view controller
    if (newVC == oldVC) return;

    // Check the newVC is non-nil otherwise expect a crash: NSInvalidArgumentException
    if (newVC) {

        // Set the new view controller frame (in this case to be the size of the available screen bounds)
        // Calulate any other frame animations here (e.g. for the oldVC)
        newVC.view.frame = CGRectMake(CGRectGetMinX(self.view.bounds), CGRectGetMinY(self.view.bounds), CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));

        // Check the oldVC is non-nil otherwise expect a crash: NSInvalidArgumentException
        if (oldVC) {

            // Start both the view controller transitions
            [oldVC willMoveToParentViewController:nil];
            [self addChildViewController:newVC];

            // Swap the view controllers
            // No frame animations in this code but these would go in the animations block
            [self transitionFromViewController:oldVC
                              toViewController:newVC
                                      duration:0.25
                                       options:UIViewAnimationOptionLayoutSubviews
                                    animations:^{}
                                    completion:^(BOOL finished) {
                                        // Finish both the view controller transitions
                                        [oldVC removeFromParentViewController];
                                        [newVC didMoveToParentViewController:self];
                                        // Store a reference to the current controller
                                        self.currentViewController = newVC;
                                    }];

        } else {

            // Otherwise we are adding a view controller for the first time
            // Start the view controller transition
            [self addChildViewController:newVC];

            // Add the new view controller view to the ciew hierarchy
            [self.view addSubview:newVC.view];

            // End the view controller transition
            [newVC didMoveToParentViewController:self];

            // Store a reference to the current controller
            self.currentViewController = newVC;
        }
    }
}

- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl *)sender {

    NSUInteger index = sender.selectedSegmentIndex;

    if (UISegmentedControlNoSegment != index) {
        UIViewController *incomingViewController = [self.allViewControllers objectAtIndex:index];
        [self cycleFromViewController:self.currentViewController toViewController:incomingViewController];
    }

}
@end

Original example (iOS 4 or before):

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    // Create the score view controller
    AddHandScoreViewController *score = [self.storyboard instantiateViewControllerWithIdentifier:@"AddHandScore"];

    // Create the penalty view controller
    AddHandPenaltyViewController *penalty = [self.storyboard instantiateViewControllerWithIdentifier:@"AddHandPenalty"];

    // Add Score and Penalty view controllers to the array
    self.allViewControllers = [[NSArray alloc] initWithObjects:score, penalty, nil];

    // Ensure the Score controller is loaded
    self.switchViewControllers.selectedSegmentIndex = 0;
    [self switchToController:[self.allViewControllers objectAtIndex:self.switchViewControllers.selectedSegmentIndex]];
}

#pragma mark - View controller switching and saving

- (void)switchToController:(UIViewController *)newVC
{
    if (newVC) {
        // Do nothing if we are in the same controller
        if (newVC == self.currentViewController) return;

        // Remove the current controller if we are loaded and shown
        if([self.currentViewController isViewLoaded]) [self.currentViewController.view removeFromSuperview];

        // Resize the new view controller
        newVC.view.frame = CGRectMake(CGRectGetMinX(self.view.bounds), CGRectGetMinY(self.view.bounds), CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));

        // Add the new controller
        [self.view addSubview:newVC.view];

        // Store a reference to the current controller
        self.currentViewController = newVC;
    }
}

- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl *)sender {

    NSUInteger index = sender.selectedSegmentIndex;

    if (UISegmentedControlNoSegment != index) {
        UIViewController *incomingViewController = [self.allViewControllers objectAtIndex:index];
        [self switchToController:incomingViewController];
    }

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...