Контроллеры представлений: Как программно переключаться между представлениями? - PullRequest
52 голосов
/ 26 мая 2009

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

У меня есть UIViewController, который действует как корневой контроллер:

@interface MyRootController : UIViewController {
    IBOutlet UIView *contentView;
}
@property(nonatomic, retain) UIView *contentView;

@end

ContentView подключен к UIView, который я добавил в качестве подпредставления к «представлению» Nib. Это имеет зеленый цвет, и я вижу его в полноэкранном режиме. Работает нормально.

Затем я создал два других View Controller примерно так же. ViewControllerA и ViewControllerB. ViewControllerA имеет синий фон, ViewControllerB имеет черный фон. Просто чтобы посмотреть, какой из них активен.

Итак, в реализации myRootController я делаю это:

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

    ViewControllerA *vcA = [[ViewControllerA alloc] initWithNib];
    [self.contentView addSubview:vcA.view];

    [cvA release];
}

Кстати, метод -initWithNib выглядит так:

- (id)initWithNib { // Load the view nib
    if (self = [super initWithNibName:@"ViewA" bundle:nil]) {
        // do ivar initialization here, if needed
    }
    return self;
}

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

  • (аннулируются) viewWillAppear: (BOOL) анимированный;
  • (пустоты) viewDidDisappear: (BOOL) анимированный; * * тысяча двадцать-одна
  • (пустот) viewDidLoad; * * 1 023

... и так далее. Кто или что, или как будут вызываться эти методы, если я сделаю это «по-моему» без контроллера панели вкладок? Я имею в виду: если я выделю класс этого ViewController, а представление станет видимым, придется ли мне позаботиться о вызове этих методов? Откуда он знает, что viewWillAppear, viewDidDisappear или viewDidLoad? Я считаю, что у Tab Bar Controller есть вся эта «хитрость» под капотом. Или я не прав?

ОБНОВЛЕНИЕ: я проверял это. Если я освобожу контроллер представления (например: ViewControllerA), я не получу сообщение журнала на viewDidDisappear. Только при выделении и инициализации ViewControllerA я получаю viewDidLoad. Но это все. Так что теперь все признаки означают хитрость UITabBarController;) и я должен выяснить, как повторить это, верно?

Ответы [ 4 ]

50 голосов
/ 26 мая 2009

Хороший пример переключения режимов представлен в главе 6 «Начало разработки iPhone». Вы можете увидеть исходный код для этого здесь: http://iphonedevbook.com/

SwitchViewController содержит код для программного изменения представления.


- (IBAction)switchViews:(id)sender
{

    if (self.yellowViewController == nil)
    {
        YellowViewController *yellowController = [[YellowViewController alloc]
                initWithNibName:@"YellowView" bundle:nil];
        self.yellowViewController = yellowController;
        [yellowController release];
    }

    [UIView beginAnimations:@"View Flip" context:nil];
    [UIView setAnimationDuration:1.25];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

    UIViewController *coming = nil;
    UIViewController *going = nil;
    UIViewAnimationTransition transition;

    if (self.blueViewController.view.superview == nil) 
    {   
        coming = blueViewController;
        going = yellowViewController;
        transition = UIViewAnimationTransitionFlipFromLeft;
    }
    else
    {
        coming = yellowViewController;
        going = blueViewController;
        transition = UIViewAnimationTransitionFlipFromRight;
    }

    [UIView setAnimationTransition: transition forView:self.view cache:YES];
    [coming viewWillAppear:YES];
    [going viewWillDisappear:YES];
    [going.view removeFromSuperview];
    [self.view insertSubview: coming.view atIndex:0];
    [going viewDidDisappear:YES];
    [coming viewDidAppear:YES];

    [UIView commitAnimations];

}
39 голосов
/ 26 мая 2009

Вы можете начать с самого простого removeFromSuperview / insertSubview и постепенно добавлять к нему код.


//SwitchViewController.h
#import 
@class BlueViewController;
@class YellowViewController;

@interface SwitchViewController : UIViewController {
    IBOutlet BlueViewController *blueViewController;
    IBOutlet YellowViewController *yellowViewController;
}
- (IBAction)switchViews:(id)sender;
@property (nonatomic, retain) BlueViewController *blueViewController;
@property (nonatomic, retain) YellowViewController *yellowViewController;
@end

//1. remove yellow view and insert blue view
- (IBAction)switchViews:(id)sender {
    if(self.blueViewController.view.superview == nil)
    {
        [yellowViewController.view removeFromSuperview];
        [self.view insertSubview:blueViewController.view atIndex:0];
    }
}

//2. appear=insert, disappear=remove
if(blueViewController.view.superview == nil)
{
    [blueViewController viewWillAppear:YES];
    [yellowViewController viewWillDisappear:YES];

    [yellowViewController.view removeFromSuperview];
    [self.view insertSubview:self.blueViewController.view atIndex:0];

    [yellowViewController viewDidDisappear:YES];
    [blueViewController viewDidAppear:YES];
}

//3. now add animation
[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
//blue view will appear by flipping from right
if(blueViewController.view.superview == nil)
{
    [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight 
                            forView:self.view cache:YES];

    [blueViewController viewWillAppear:YES];
    [yellowViewController viewWillDisappear:YES];

    [yellowViewController.view removeFromSuperview];
    [self.view insertSubview:self.blueViewController.view atIndex:0];

    [yellowViewController viewDidDisappear:YES];
    [blueViewController viewDidAppear:YES];
}
[UIView commitAnimations];

21 голосов
/ 26 мая 2009

Если я правильно понимаю, то, что вы пытаетесь достичь, довольно просто.

Просто добавьте UINavigationController в ваш делегат приложения и выполните:

[navigationController pushView:vcA];

Делегаты будут называться соответственно:

  • (аннулируются) viewWillAppear: (BOOL) анимированный;
  • (пустоты) viewDidDisappear: (BOOL) анимированные;
  • (пустот) viewDidLoad;

А когда вы хотите открыть представление и нажать еще один:

[navigationController popViewControllerAnimated:true];
[navigationController pushView:vcB];

Если вы не хотите показывать навигационный контроллер, просто используйте:

[navigationBar setHidden:YES];

Где navigationBar - это UINavigationBar, соответствующая вашему UINavigationController.

2 голосов
/ 15 декабря 2012

Это может быть старая проблема, но недавно я столкнулся с той же проблемой, и мне было трудно найти что-то, что сработало. Я хотел переключиться между двумя дополнительными контроллерами представления, но я хотел, чтобы переключение было анимированным (встроенные анимации работают нормально), и я хотел, чтобы он был совместим с раскадровками, если это возможно.

Для использования преимуществ встроенного перехода прекрасно работает метод +transitionFromView:toView:duration:options:completion: UIView. Но это только переходы между представлениями, а не контроллеры представления.

Для перехода между контроллерами представления целиком, а не просто представлениями, необходимо создать собственный UIStoryboardSegue. Независимо от того, используете ли вы раскадровки, этот подход позволяет инкапсулировать весь переход и управлять передачей соответствующей информации от одного контроллера представления к другому. Это включает только подклассы UIStoryboardSegue и переопределение одного метода, -perform.

Для справочной реализации см. RAFlipReplaceSegue, точный пользовательский переход, который я собрал, используя этот подход. В качестве бонуса он также заменяет старый контроллер вида новым, если он находится в стеке UINavigationController.

...