Изменение контроллера просмотра при изменении Segmented Control

Эта проблема сводит меня с ума. Я пытаюсь изменить viewController, когда пользователь изменяет выбранную "вкладку" сегментарного элемента управления. Я провел пару часов исследований и не смог найти ответ, который работает или делается через раскадровку.

Это действительно беспокоит меня, поскольку установка приложения вкладки настолько проста, но попытка использовать сегментированный элемент управления, как приложение вкладки, просто не работает. Я уже знаю, как определить, какой индекс выбран в сегментированном элементе управления. Как я могу это достичь?

Большое спасибо.

Ответ 1

Я бы сказал, что гораздо проще изменить subviews в UIViewController, вы можете настроить свои подпрограммы в своих раскадках и подключить их с помощью IBOulets в своем контроллере, вы можете установить свойство hidden ваших просмотров к YES или NO в зависимости от выбранного элемента управления.

Теперь, если вы используете подход @Robotic Cat, который также является хорошим решением, вы можете иметь немного больше модульности в том, как работает ваше приложение, учитывая, что вам нужно будет разместить всю свою логику в одном контроллере с помощью представленного мной решения.

Ответ 2

ПРИМЕЧАНИЕ. Ответ обновляется с помощью кода локализации контроллера для iOS 5+, включая раздел @interface

В моем приложении у меня есть контроллер представления с элементом управления сегментами в панели навигации и нажатием на переключатели просмотра "tabs". Основная идея состоит в том, чтобы иметь массив контроллеров представлений и переключаться между ними, используя индекс сегмента (и indexDidChangeForSegmentedControl IBAction.

Пример кода (iOS 5 или новее) из моего приложения (это для 2 контроллеров представлений, но оно тривиально расширено для нескольких контроллеров представления); код немного длиннее, чем для iOS 4, но сохранит график объекта неповрежденным. Кроме того, он использует 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

Пример оригинала (iOS 4 или ранее):

// 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];
    }

}

Ответ 3

UISegmentedControl немного отличается тем, что у него нет протокола делегата, вам нужно использовать стиль "добавить цель". В вашем случае то, что вы хотите сделать, это добавить цель, которая будет уведомляться при изменении UISegmentedControl (что, скорее всего, является контроллером родительского представления), а затем эта цель может работать с переключением вкладок.

Например:

[self.mainSegmentedControl addTarget:self action:@selector(changedSegmentedControl:) forControlEvents:UIControlEventValueChanged];

В этом примере код вызывается из некоторого вида/контроллера, который имеет доступ к переменной для сегментированного элемента управления. Мы добавляем себя, чтобы вызвать вызванный метод changedSegmentedControl:.

Тогда у вас будет другой метод:

- (void)changedSegmentedControl:(id)sender
{
   UISegmentedControl *ctl = sender;
   NSLog(@"Changed value of segmented control to %d", ctl.selectedSegmentIndex);
   // Code to change View Controller goes here
}

Примечание: это непроверенный код, записанный из памяти - пожалуйста, обратитесь к документации.

Ответ 4

Взгляните на этот pod: https://github.com/xmartlabs/XLMailBoxContainer. Это делает анимацию пользовательского интерфейса среди контроллеров представления. Эти контроллеры могут расширять UITableViewController или любой другой контроллер представления.

Я надеюсь, что это поможет вам!