Как программно загрузить раскадровку из класса?

183

Моя проблема в том, что я искал способ использовать как раскадровку, так и xib . Но я не могу найти правильный способ программной загрузки и отображения раскадровки. Проект начинался с xib, и сейчас очень сложно вложить все xib-файлы в раскадровку. Поэтому я искал способ сделать это в коде, например, alloc, init, pushдля viewControllers. В моем случае у меня есть только один контроллер в раскадровке: UITableViewControllerсо статическими ячейками с некоторым контентом, который я хочу показать. Если кто-то знает, как правильно работать как с xib, так и с раскадровкой без огромного рефакторинга, я буду признателен за любую помощь.

кококо
источник

Ответы:

373

В раскадровке перейдите к инспектору атрибутов и установите идентификатор контроллера представления. Затем вы можете представить этот контроллер представления, используя следующий код.

UIStoryboard *sb = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:@"myViewController"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];
Джеймс Бейт
источник
65
[sb instantiateInitialViewController]удобно, если вы хотите начать с контроллера представления сцены по умолчанию.
нарисовал
Джеймс, спасибо! Я довольно долго искал, пытаясь выяснить, как создать экземпляр представления Storyboard. Ваш ответ (и вопрос Кококо) очень воодушевляет.
bejonbee
В коде Джеймса Бейта необходимо повторно использовать этот UIViewControler * vc, если он переключается взад и вперед с текущим контроллером представления. Я на собственном горьком опыте выяснил, что vc застревает и подключается к перу раскадровки до тех пор, пока пользователь не нажимает кнопку в новом представлении, и теперь есть утечка памяти с отброшенным vc из предыдущих заклинаний этого кода.
SWoo 06
11
Если кто-то хочет знать, как это сделать в делегате приложения, вы замените [self presentViewcontroller]логику этими строками в следующем порядке: 1) self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];2) self.window.rootViewController = vc;и 3) [self.window makeKeyAndVisible];. Вы также, вероятно, можете избавиться от modalTransitionStyleстроки, потому что это не модальный переход от делегата приложения.
lewiguez
К вашему сведению, если вы хотите «подтолкнуть» новую раскадровку вместо модального всплытия, посмотрите ответ chaithraVeeresh.
Адам Джонс
76

Swift 3

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "viewController")
self.navigationController!.pushViewController(vc, animated: true)

Swift 2

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("viewController")
self.navigationController!.pushViewController(vc, animated: true)

Предпосылка

Назначьте идентификатор раскадровки своему контроллеру представления.

ID раскадровки

IB> Показать инспектора удостоверений> Идентификатор> Идентификатор раскадровки

Swift (наследие)

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("viewController") as? UIViewController
self.navigationController!.pushViewController(vc!, animated: true)

Изменить: Swift 2 предложен в комментарии Фреда А.

если вы хотите использовать без навигационного контроллера, вы должны использовать следующее:

    let Storyboard  = UIStoryboard(name: "Main", bundle: nil)
    let vc = Storyboard.instantiateViewController(withIdentifier: "viewController")
    present(vc , animated: true , completion: nil)
SwiftАрхитектор
источник
1
В Swift 2 вам не нужно добавлять «as? UIViewController», компилятор определяет это автоматически
Фредерик Адда
2
или вы можете просто self.storyboardобъединить строки 1 и 2
Дорогая,
17

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

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
DetailViewController *detailViewController = [storyboard instantiateViewControllerWithIdentifier:@"DetailViewController"];
[self.navigationController pushViewController:detailViewController animated:YES];
ChaithraVeeresh
источник
5

Попробуй это

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:@"Login"];

[[UIApplication sharedApplication].keyWindow setRootViewController:vc];
Адетилой Филип Кехинде
источник
Используйте это, если вы не используете UINavigationController, как показано в других ответах
latenitecoder
2

в Swift
NavigationController и pushController вы можете заменить на

present(vc, animated:true , completion: nil)
Тарик
источник
1

Для быстрых 3 и 4 это можно сделать. Хорошая практика - установить имя Storyboard равным StoryboardID.

enum StoryBoardName{
   case second = "SecondViewController"
}
extension UIStoryBoard{
   class func load(_ storyboard: StoryBoardName) -> UIViewController{
      return UIStoryboard(name: storyboard.rawValue, bundle: nil).instantiateViewController(withIdentifier: storyboard.rawValue)
   }
}

а затем вы можете загрузить свою раскадровку в свой ViewController следующим образом:

class MyViewController: UIViewController{
     override func viewDidLoad() {
        super.viewDidLoad()
        guard let vc = UIStoryboard.load(.second) as? SecondViewController else {return}
        self.present(vc, animated: true, completion: nil)
     }

}

Когда вы создаете новую раскадровку, просто установите то же имя в StoryboardID и добавьте имя раскадровки в свое перечисление « StoryBoardName »

Ганди Мена
источник
0

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

UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateInitialViewController];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];
user938797
источник
0

Приведенное ниже расширение позволит вам загрузить файл Storyboardи связанный с ним файл UIViewController. Пример. Если у вас есть UIViewControllerимя ModalAlertViewControllerи раскадровка с именем «ModalAlert», например

let vc: ModalAlertViewController = UIViewController.loadStoryboard("ModalAlert")

Загрузит Storyboardи UIViewControllerи vcбудет типа ModalAlertViewController. Примечание. Предполагается, что идентификатор раскадровки имеет то же имя, что и раскадровка, и что раскадровка помечена как « Исходный контроллер представления» .

extension UIViewController {
    /// Loads a `UIViewController` of type `T` with storyboard. Assumes that the storyboards Storyboard ID has the same name as the storyboard and that the storyboard has been marked as Is Initial View Controller.
    /// - Parameter storyboardName: Name of the storyboard without .xib/nib suffix.
    static func loadStoryboard<T: UIViewController>(_ storyboardName: String) -> T? {
        let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
        if let vc = storyboard.instantiateViewController(withIdentifier: storyboardName) as? T {
            vc.loadViewIfNeeded() // ensures vc.view is loaded before returning
            return vc
        }
        return nil
    }
}
Норман
источник