Появилась нужна использовать в проекте и UINavigationController, и UITabBarController одновременно. Два способа как это сделать.
Создадим пустой проект. Прописывать контроллеры будем вручную. Итак, у нас есть AppDelegate.h и AppDelegate.m.
Способ 1. UINavigationController внутри UITabBarController. (от @vox_humana)
В этом способе в приложении всегда есть Tab Bar, он всегда виден и между табами всегда можно переключаться. Внутри одного из табов (или можно сделать во всех) есть вид с UINavigationController, в котором можно делать перемещение между видами с помощью push и pop.
Создадим два новый файла типа UIViewController subclass (с галкой with XIB for user interface). Назовём их, скажем, FirstViewController и SecondViewController. Это будут два наших вида, которые будут выводиться в двух табах.
Наш AppDelegate.h в пустом проекте выглядит так:
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
Нам нужно добавить новую @property c UITabBarController:
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UITabBarController *tabBarController;
@end
Далее идём в AppDelegate.m. Здесь нужно импортировать созданные FirstViewController и SecondViewController, а также сделать @synthesize для табов:
#import "AppDelegate.h"
#import "FirstViewController.h"
#import "SecondViewController.h"
@implementation AppDelegate
@synthesize window = _window;
@synthesize tabBarController = _tabBarController;
Внутри метода didFinishLaunchingWithOptions прописываем следующее:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// создаём окно для приложения по размеру экрана
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// создаём два экземпляра UIViewController
UIViewController *viewController1, *viewController2;
// первый вид инициализируем с интерфейсом нашего первого контроллера
viewController1 = [[UINavigationController alloc] initWithRootViewController:[[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil]];
// второй вид инициализируем с интерфейсом нашего второго контроллера
viewController2 = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
// подключаем наши виды к таб-бару
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
// как основной контроллер приложению ставим tabBarController
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
Теперь при запуске у нас появится таб-бар внизу экрана. В каждом табе будет по контроллеру. Первый контроллер (viewController1) будет иметь в себе UINavigationController, что позволит нам делать push и pop видов. Для примера добавим ещё один UIViewController subclass (с галкой with XIB for user interface). Назовём его MyViewController. Таким образом у нас уже будет 3 UIViewController в проекте:
Поскольку у нас viewController1 (он же FirstViewController) содержит в себе UINavigationController, то добавим в него какое-нибудь действие, чтобы перейти в наш контроллер. Сначала в начале FirstViewController.m сделаем #import "DetailViewController.h", затем добавим метод:
- (IBAction)pushToMyController:(id)sender {
MyViewController * childControl = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
[[self navigationController] pushViewController:childControl animated:YES];
}
Ну и само собой не забудем объявить его в FirstViewController.h:
- (IBAction)pushToMyController:(id)sender;
Добавим в FirstViewController.xib кнопку и свяжем её через Connection Inspector с нашим action:
Готово. Можно запускать. На выходе получаем вот такой результат:
По такому принципу сделано приложение Dropbox для iPhone, например. Скачать готовый пример.
Способ 2. UITabBarController внутри UINavigationController.
Начинаем с того, что создаём RootViewController. Ему нужно создать @property:
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
Добавить в xib-файл UITabBarController, связать его в Connections Inspector. Создаём два вида в проекте - FirstViewController и SecondViewController, для UITabBarController, что внутри RootViewController.xib привязываем табы к этим видам.
Приведу начало файла AppDelegate.m:
#import "AppDelegate.h"
#import "RootViewController.h"
@implementation AppDelegate
@synthesize window = _window;
@synthesize viewController = _viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// создаём окно
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// создаём главный контроллер
self.viewController = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:nil];
// создаём UINavigationController
navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
// назначаем главным контроллером UINavigationController
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
Общая суть в том, что self.window.rootViewController - это UINavigationController. У приложения есть RootViewController со своим xib. Его можно оставить пустым, но ему нужно прописать @property:
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
Когда вид RootViewController загружается - мы сразу делаем push в наш tabBarController. Таким образом первое, что видно при запуске - это табы и верхнюю панель с кнопкой назад, которую в этом месте можно скрыть и показывать только дальше где-то.
Главный плюс - внутри видов, которые грузятся внутри UITabBarController - можно в коде делать перемещение основного экрана в другие виды и возвращаться обратно. Видео:
По такому принципу сделано приложение ВКонтакте для iPhone. Реализовано в моём примере, пожалуй, не идеально, при желании можно допилить, но работает. Скачать пример.
На будущее пригодится, заодно сам ещё раз всё проделал и закрепил.