Изменить содержимое просмотра контейнера с помощью вкладок в iOS

Я пытаюсь сделать форму, которая охватывает три вкладки. Вы можете увидеть на скриншоте ниже, где будут расположены вкладки. Когда пользователь нажимает на вкладку, представление "Контейнер" должно обновляться и отображать определенный контроллер представления, который у меня есть.

просмотр контроллера

Tab 1 = View Controller 1

Tab 2 = View Controller 2

Tab 3 = View Controller 3

Контроллер представления, показанный выше, имеет класс PPAddEntryViewController.m. Я создал выход для представления "Контейнер" в этом классе, и теперь у меня есть свойство "Вид контейнера":

@property (weak, nonatomic) IBOutlet UIView *container;

У меня также есть свои IBActions для моих вкладок:

- (IBAction)tab1:(id)sender {
  //...
}
- (IBAction)tab2:(id)sender {
  //...
}
- (IBAction)tab3:(id)sender {
  //...
}

Как установить контейнер в этих IBActions, чтобы изменить контроллер представления, который содержит представление контейнера?

Среди всего прочего я попробовал вот что:

UIViewController *viewController1 = [self.storyboard instantiateViewControllerWithIdentifier:@"vc1"];
_container.view = viewController1;

... но это не работает. Заранее спасибо.

5 ответов

Решение

Недавно я нашел идеальный пример кода для того, что я пытался сделать. Он включает в себя реализацию раскадровки и все соответствующие сегменты и код. Это было действительно полезно.

https://github.com/mhaddl/MHCustomTabBarController

Переключение с использованием раскадровки, автоматического макета или нет, какой-то кнопки и ряда дочерних контроллеров представления

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

В раскадровке вы можете подключить только один встроенный переход к представлению контейнера. Итак, вы создаете промежуточный контроллер обработки. Сделайте встраивание segue и присвойте ему идентификатор, например EmbededSegueIdentifier.

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

Контроллер родительского представления

@property (weak, nonatomic) MyContainerViewController *myContainerViewController;

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"EmbeddedSegueIdentifier"]) {
        self.myContainerViewController = segue.destinationViewController;
    }
}

Вам должно быть довольно легко делегировать контроллеру контейнера нажатия кнопки.

Контейнер Контроллер

Этот следующий фрагмент кода был частично заимствован из нескольких источников, но ключевое изменение заключается в том, что используется автоматическое размещение, а не явные кадры. Ничто не мешает вам просто поменять строки [self addConstraintsForViewController:] за viewController.view.frame = self.view.bounds, В раскадровке этот Контроллер Представления Контейнера не делает больше ничего, что связано с целевыми дочерними контроллерами представления.

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"%s", __PRETTY_FUNCTION__);

    [self performSegueWithIdentifier:@"FirstViewControllerSegue" sender:nil];
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    UIViewController *destinationViewController = segue.destinationViewController;

    if ([self.childViewControllers count] > 0) {
        UIViewController *fromViewController = [self.childViewControllers firstObject];
        [self swapFromViewController:fromViewController toViewController:destinationViewController];
    } else {
        [self initializeChildViewController:destinationViewController];
    }
}

- (void)initializeChildViewController:(UIViewController *)viewController
{
    [self addChildViewController:viewController];
    [self.view addSubview:viewController.view];
    [self addConstraintsForViewController:viewController];

    [viewController didMoveToParentViewController:self];
}

- (void)swapFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController
{
    [fromViewController willMoveToParentViewController:nil];
    [self addChildViewController:toViewController];
    [self transitionFromViewController:fromViewController toViewController:toViewController duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
        [self addConstraintsForViewController:toViewController];
        [fromViewController removeFromParentViewController];
        [toViewController didMoveToParentViewController:self];
    }];
}

- (void)addConstraintsForViewController:(UIViewController *)viewController
{
    UIView *containerView = self.view;
    UIView *childView = viewController.view;
    [childView setTranslatesAutoresizingMaskIntoConstraints:NO];
    [containerView addSubview:childView];

    NSDictionary *views = NSDictionaryOfVariableBindings(childView);
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[childView]|"
                                                                          options:0
                                                                          metrics:nil
                                                                            views:views]];
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[childView]|"
                                                                          options:0
                                                                          metrics:nil
                                                                            views:views]];
}



#pragma mark - Setters

- (void)setSelectedControl:(ViewControllerSelectionType)selectedControl
{
    _selectedControl = selectedControl;

    switch (self.selectedControl) {
        case kFirstViewController:
            [self performSegueWithIdentifier:@"FirstViewControllerSegue" sender:nil];
            break;
        case kSecondViewController:
            [self performSegueWithIdentifier:@"SecondViewControllerSegue" sender:nil];
            break;
        default:
            break;
    }
}

Пользовательские сегы

Последнее, что вам нужно, это пользовательский переход, который ничего не делает, отправляясь в каждый пункт назначения с соответствующим идентификатором перехода, который вызывается из контроллера представления контейнера. Если вы не введете пустой метод выполнения, приложение будет аварийно завершено. Обычно вы можете сделать некоторые пользовательские анимации перехода здесь.

@implementation SHCDummySegue

@interface SHCDummySegue : UIStoryboardSegue

@end

- (void)perform
{
    // This space intentionally left blank
}

@end

Обновление: UITabBarController - рекомендуемый путь, как вы узнали ранее. Если вы хотите иметь собственную высоту, вот хорошее начало: Мой способ настройки панели вкладок UITabBarController - ответ Stackru

Начиная с iOS 5+ у вас есть доступ к настройке внешнего вида через этот API; Ссылка на протокол UIAppearance. Вот хороший урок для этого: Как настроить фон и внешний вид панели вкладок

Самый очевидный способ добиться того, что вы ищете, - это просто управлять 3 различными контейнерами (они являются простыми UIViews) и реализовывать каждый из них для хранения любого представления контента, которое вам нужно для каждой вкладки (используйте свойство hidden контейнеров).

Вот пример того, чего можно достичь с помощью различных контейнеров:

Встроить контроллеры представления

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

Иметь переменную-член для хранения viewController:

UIViewController *selectedViewController;

Теперь в IBActions, переключите это И представление. например

- (IBAction)tab1:(id)sender {
     UIViewController *viewController1 = [self.storyboard instantiateViewControllerWithIdentifier:@"vc1"];

     _container.view = viewController1.view;
     selectedViewController = viewController1;
}

чтобы запустить представление действительно появилось и вызвать вещи removeChildViewController, didMoveToParent, addChildViewController, didMoveToParent

Я получил это, чтобы работать с помощью UITabBarController. Чтобы использовать пользовательские вкладки, мне пришлось создать подкласс TabBarController и добавить кнопки к контроллеру в коде. Затем я слушаю события нажатия на кнопки и устанавливаю selectedIndex для каждой вкладки.

Это было довольно просто, но в моей раскадровке много мусора для чего-то такого простого, как 3 вкладки.

Другие вопросы по тегам