如何以编程方式从课堂加载故事板?

Posted

技术标签:

【中文标题】如何以编程方式从课堂加载故事板?【英文标题】:How can I load storyboard programmatically from class? 【发布时间】:2012-03-27 19:34:33 【问题描述】:

我的问题是我正在寻找同时使用 storyboardxib 的方法。但是我找不到以编程方式加载和显示故事板的正确方法。项目开始使用 xib 开发,现在很难将所有 xib 文件嵌套在情节提要中。所以我一直在寻找一种在代码中实现它的方法,比如使用 alloc, init, push 用于 viewControllers。在我的例子中,我在情节提要中只有一个控制器:UITableViewController,它有一些我想要显示的内容的静态单元格。如果有人知道在不进行大量重构的情况下使用 xib 和故事板的正确方法,我将不胜感激。

【问题讨论】:

【参考方案1】:

在您的故事板中,转到属性检查器并设置视图控制器的标识符。然后,您可以使用以下代码呈现该视图控制器。

UIStoryboard *sb = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:@"myViewController"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];

【讨论】:

如果您想从场景的默认视图控制器开始,[sb instantiateInitialViewController] 很方便。 詹姆斯,谢谢!我一直在寻找相当长的时间来试图弄清楚如何实例化 Storyboard 的视图。您的答案(和 kokoko 的问题)令人耳目一新。 在 James Beith 的代码中,如果 UIViewControler *vc 与当前视图控制器来回切换,则必须重用它。我发现 vc 一直存在并连接到情节提要笔尖的困难方式,直到用户按下新视图上的按钮,现在该代码的先前咒语中丢弃的 vc 存在内存泄漏。跨度> 如果有人想知道如何在应用程序委托中执行此操作,请按以下顺序将 [self presentViewcontroller] 逻辑替换为这些行:1) self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 2) self.window.rootViewController = vc; 和 3 )[self.window makeKeyAndVisible];。您也可以去掉 modalTransitionStyle 行,因为这不是来自应用委托的模态转换。 仅供参考,如果您想“推动”新故事板而不是模态弹出,请查看 chaithraVeeresh 的答案。【参考方案2】:

斯威夫特 3

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

斯威夫特 2

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

先决条件

为您的视图控制器分配一个 Storyboard ID

IB > 显示身份检查器 > 身份 > 故事板 ID

Swift(旧版)

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

编辑:Fred A. 的评论中建议使用 Swift 2

如果你想在没有任何 navigationController 的情况下使用,你必须使用如下:

    let Storyboard  = UIStoryboard(name: "Main", bundle: nil)
    let vc = Storyboard.instantiateViewController(withIdentifier: "viewController")
    present(vc , animated: true , completion: nil)

【讨论】:

在 Swift 2 中,不需要添加“as?UIViewController”,编译器会自动判断 或者你可以做self.storyboard并合并line1&2【参考方案3】:

在属性检查器中给出该视图控制器的标识符,下面的代码适用于我

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

【讨论】:

【参考方案4】:

试试这个

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

[[UIApplication sharedApplication].keyWindow setRootViewController:vc];

【讨论】:

如果您不使用 UINavigationController,请使用此选项,如其他答案所示【参考方案5】:

在 swiftNavigationControllerpushController 中您可以替换为

present(vc, animated:true , completion: nil)

【讨论】:

【参考方案6】:

你总是可以直接跳转到根控制器:

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

【讨论】:

【参考方案7】:

下面的扩展将允许您加载Storyboard,它与UIViewController 相关联。示例:如果您有一个名为 ModalAlertViewControllerUIViewController 和一个名为“ModalAlert”的故事板,例如

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

将同时加载StoryboardUIViewControllervc 的类型为ModalAlertViewController注意假设storyboard的Storyboard ID与storyboard同名,并且storyboard已经被标记为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
    

【讨论】:

【参考方案8】:

对于 swift 4 和 5,您可以这样做。好的做法是将 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 中加载 Storyboard:

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)
     

当您创建新的 Storyboard 时,只需在 StoryboardID 上设置相同的名称并在您的枚举“StoryBoardName”中添加 Storyboard 名称

【讨论】:

以上是关于如何以编程方式从课堂加载故事板?的主要内容,如果未能解决你的问题,请参考以下文章

如何将项目从使用故事板转换为不再使用故事板?

如何以编程方式将 UIImageView 添加到 UIStackView(故事板)

故事板中的子类 viewController 并以编程方式从子类更改 UI

如何在故事板上显示以编程方式添加的元素?

如何在故事板或XIB中以编程方式分配uiview?

故事板集合视图拒绝在以编程方式创建的按钮前面