Изменить содержимое просмотра контейнера с помощью вкладок в 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 ответов
Недавно я нашел идеальный пример кода для того, что я пытался сделать. Он включает в себя реализацию раскадровки и все соответствующие сегменты и код. Это было действительно полезно.
Переключение с использованием раскадровки, автоматического макета или нет, какой-то кнопки и ряда дочерних контроллеров представления
Вы хотите добавить контейнерное представление к вашему представлению, и когда кнопки, которые "переключают" контроллеры дочерних представлений, нажаты, запускают соответствующий переход и выполняют правильную работу по настройке.
В раскадровке вы можете подключить только один встроенный переход к представлению контейнера. Итак, вы создаете промежуточный контроллер обработки. Сделайте встраивание 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 вкладки.