Comment puis-je charger le storyboard par programme à partir de la classe?

183

Mon problème est que je cherchais un moyen d'utiliser à la fois le storyboard et xib . Mais je ne trouve pas le moyen approprié de charger et d'afficher le storyboard par programmation. Le projet a commencé à se développer avec xib, et maintenant il est très difficile d'imbriquer tous les fichiers xib dans le storyboard. Je cherchais donc un moyen de le faire dans le code, comme avec alloc, init, pushpour viewControllers. Dans mon cas, je n'ai qu'un seul contrôleur dans le storyboard:, UITableViewControllerqui a des cellules statiques avec du contenu que je veux montrer. Si quelqu'un sait comment travailler à la fois avec xib et storyboard sans refactoring énorme, j'apprécierai toute aide.

Kokoko
la source

Réponses:

373

Dans votre storyboard, accédez à l'inspecteur d'attributs et définissez l'identifiant du contrôleur de vue. Vous pouvez ensuite présenter ce contrôleur de vue à l'aide du code suivant.

UIStoryboard *sb = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:@"myViewController"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];
James Beith
la source
65
[sb instantiateInitialViewController]est pratique si vous souhaitez démarrer sur le contrôleur de vue par défaut de la scène.
tirage le
James, merci! Je cherche depuis un certain temps à essayer de comprendre comment instancier la vue d'un Storyboard. Votre réponse (et la question de Kokoko) sont des plus rafraîchissantes à trouver.
bejonbee
Sur le code de James Beith, il faut réutiliser ce UIViewControler * vc s'il est commuté d'avant en arrière avec le viewcontroller actuel. J'ai découvert à la dure que le vc reste et est câblé à la pointe du storyboard jusqu'à ce que l'utilisateur appuie sur un bouton sur la nouvelle vue, et il y a maintenant une fuite de mémoire avec ce vc rejeté des incantations précédentes de ce code.
SWoo
11
Si quelqu'un souhaite savoir comment procéder dans le délégué d'application, remplacez la [self presentViewcontroller]logique par ces lignes dans l'ordre suivant: 1) self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];2) self.window.rootViewController = vc;et 3) [self.window makeKeyAndVisible];. Vous pouvez également probablement vous débarrasser de la modalTransitionStyleligne, car il ne s'agit pas d'une transition modale du délégué d'application.
lewiguez
FYI, si vous voulez "pousser" le nouveau storyboard au lieu de pop up modalement, regardez la réponse de chaithraVeeresh.
Adam Johns
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)

Prérequis

Attribuez un ID de Storyboard à votre contrôleur de vue.

ID du storyboard

IB> Afficher l'inspecteur d'identité> Identité> ID du storyboard

Swift (héritage)

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

Edit: Swift 2 suggéré dans un commentaire de Fred A.

si vous souhaitez utiliser sans navigationController, vous devez utiliser comme suit:

    let Storyboard  = UIStoryboard(name: "Main", bundle: nil)
    let vc = Storyboard.instantiateViewController(withIdentifier: "viewController")
    present(vc , animated: true , completion: nil)
SwiftArchitect
la source
1
Dans Swift 2, vous n'avez pas besoin d'ajouter "as? UIViewController", le compilateur le détermine automatiquement
Frédéric Adda
2
ou vous pouvez simplement faire self.storyboardet fusionner les lignes 1 et 2
Honey
17

Dans l'inspecteur d'attributs, donnez l'identifiant de ce contrôleur de vue et le code ci-dessous fonctionne pour moi

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
DetailViewController *detailViewController = [storyboard instantiateViewControllerWithIdentifier:@"DetailViewController"];
[self.navigationController pushViewController:detailViewController animated:YES];
chaithraVeeresh
la source
5

Essaye ça

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

[[UIApplication sharedApplication].keyWindow setRootViewController:vc];
Adetiloye Philip Kehinde
la source
Utilisez ceci si vous n'utilisez pas un UINavigationController comme indiqué dans d'autres réponses
latenitecoder
2

dans swift
NavigationController et pushController, vous pouvez remplacer

present(vc, animated:true , completion: nil)
Tarik
la source
1

Pour swift 3 et 4 , vous pouvez le faire. La bonne pratique consiste à définir le nom de Storyboard égal à 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)
   }
}

puis vous pouvez charger votre Storyboard dans votre ViewController comme ceci:

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)
     }

}

Lorsque vous créez un nouveau Storyboard, définissez simplement le même nom sur StoryboardID et ajoutez le nom du Storyboard dans votre énumération " StoryBoardName "

Gandhi Mena
la source
0

Vous pouvez toujours accéder directement au contrôleur racine:

UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateInitialViewController];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];
user938797
la source
0

L'extension ci-dessous vous permettra de charger un Storyboardet il est associé UIViewController. Exemple: Si vous avez un UIViewControllernommé ModalAlertViewControlleret un storyboard nommé "ModalAlert", par exemple

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

Charge à la fois le Storyboardet UIViewControlleret vcsera de type ModalAlertViewController. Remarque Suppose que l'ID du storyboard du storyboard a le même nom que le storyboard et que le storyboard a été marqué comme Is Initial View Controller .

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
    }
}
normand
la source