【问题标题】:Creating a segue programmatically以编程方式创建 segue
【发布时间】:2012-03-29 07:15:01
【问题描述】:

我有一个共同的UIViewController,我所有的UIViewsControllers 都可以扩展以重用一些共同的操作。

我想在这个“公共”UIViewController 上设置一个转场,以便所有其他 UIViewControllers 继承。

我正试图弄清楚如何以编程方式做到这一点。

我想这个问题也可能是我如何为我所有的UIViewControllers 设置一个segue 而无需进入故事板并手动完成。

【问题讨论】:

    标签: ios objective-c segue


    【解决方案1】:

    我想我会添加另一种可能性。您可以做的一件事是,您可以使用未附加到动作的 segue 连接故事板中的两个场景,然后以编程方式触发视图控制器内的 segue。执行此操作的方式是,您必须从故事板场景底部的文件所有者图标(即连续场景)拖动,然后向右拖动到目标场景。我会放一张图片来帮助解释。

    将显示“手动转场”弹出窗口。我选择 Push 作为类型。点击小方块并确保您在属性检查器中。给它一个标识符,您将使用它在代码中引用它。

    好的,接下来我将使用编程栏按钮项进行转场。在 viewDidLoad 或其他地方,我将使用以下代码在导航栏上创建一个按钮项:

    UIBarButtonItem *buttonizeButton = [[UIBarButtonItem alloc] initWithTitle:@"Buttonize"
                                                                        style:UIBarButtonItemStyleDone
                                                                       target:self
                                                                       action:@selector(buttonizeButtonTap:)];
    self.navigationItem.rightBarButtonItems = @[buttonizeButton];
    

    好的,注意选择器是 buttonizeButtonTap:。因此,为该按钮编写一个 void 方法,在该方法中,您将像这样调用 segue:

    -(void)buttonizeButtonTap:(id)sender{
        [self performSegueWithIdentifier:@"Associate" sender:sender];
        }
    

    调用 prepareForSegue 时需要 sender 参数来识别按钮。 prepareForSegue 是一个框架方法,您将在其中实例化您的场景并传递它完成工作所需的任何值。这是我的方法的样子:

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
        if ([[segue identifier] isEqualToString:@"Associate"])
        {
            TranslationQuizAssociateVC *translationQuizAssociateVC = [segue destinationViewController];
            translationQuizAssociateVC.nodeID = self.nodeID; //--pass nodeID from ViewNodeViewController
            translationQuizAssociateVC.contentID = self.contentID;
            translationQuizAssociateVC.index = self.index;
            translationQuizAssociateVC.content = self.content;
        }
    }
    

    好的,刚刚测试过,它可以工作。希望对你有帮助。

    【讨论】:

    • @MichaelRowe 这如何消除对 segues 的需求?如我所见,您仍然必须将 Storyboard 拖放到目标控制器..
    • @MichaelRowe 这并不能消除对转场的需要。这样做的目的是让您在内置于代码中而不是在界面构建器中的视图控制器之间进行切换。
    • @Matt 它实际上只是让我彻底重新思考如何设置我的应用程序......在完全重写所有 UI 之后,我不再使用任何 segues..
    • @cocoanut 我收到错误消息,因为“应用程序试图以模态方式呈现活动控制器”对此有任何帮助..
    • 手动转场“推送”已弃用,请使用“显示”。 This answer 有更多详细信息。 @smileBot 请更新答案。
    【解决方案2】:

    根据定义,segue 不能真正独立于故事板而存在。它甚至出现在班级名称中:UIStoryboardSegue。您不会以编程方式创建 segue - 它是故事板运行时为您创建它们。您通常可以在视图控制器的代码中调用 performSegueWithIdentifier:,但这依赖于在情节提要中已经设置了一个 segue 以供参考。

    我认为您要问的是如何在通用视图控制器(基类)中创建一个方法,该方法将转换为新的视图控制器,并由所有派生类继承。你可以通过为你的基类视图控制器创建一个像这样的方法来做到这一点:

    - (IBAction)pushMyNewViewController
    {
        MyNewViewController *myNewVC = [[MyNewViewController alloc] init];
    
        // do any setup you need for myNewVC
    
        [self presentModalViewController:myNewVC animated:YES];
    }
    

    然后在您的派生类中,在单击相应按钮或选择表格行或其他任何情况时调用该方法。

    【讨论】:

    • 谢谢。很遗憾我们不能以编程方式做到这一点。它确实会提高源代码的质量(减少重复总是好的)。我会同意你的建议。
    • @jonkroll 是否可以从 switch 语句调用/执行 segue,即基于我拥有的索引?
    • @codejunkie:是的,你可以这样做。为此,您将使用名为 performSegueWithIdentifier:sender:UIViewController 方法。
    • 我一直在以编程方式创建和执行 segue(请参阅我的答案)。如果你的答案是正确的,我的代码有什么问题吗?
    • iOS 6+ 的更新:UIViewpresentModalViewController:animated: 已弃用。来自docs- (在 iOS 6.0 中已弃用。使用 presentViewController:animated:completion: 代替。)
    【解决方案3】:

    我一直在使用此代码来实例化我的自定义 segue 子类并以编程方式运行它。它似乎工作。这有什么问题吗?我很困惑,阅读了所有其他答案,说这是不可能的。

    UIViewController *toViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"OtherViewControllerId"];
    MyCustomSegue *segue = [[MyCustomSegue alloc] initWithIdentifier:@"" source:self destination:toViewController];
    [self prepareForSegue:segue sender:sender];
    [segue perform];
    

    【讨论】:

    • 它是UIStoryboardSegue的自定义子类。
    • @MarkAmery 很多人(包括我)避免使用故事板。它们很难合并,并且没有编译时检查我传递给 performSegueWithIdentifier: 的 ID 是否真的在情节提要中定义。如果我自己创建 segue,我会避免所有问题。
    • 谢谢美女让-菲利普!我有许多页面都需要使用自定义 segue 动画退出主菜单。在故事板上创建所有链接将是荒谬的。非常有用的代码,谢谢。
    • 我同意让-菲利普的观点。管理故事板是一件令人头疼的事情。当然,通过创建几个视图并在此处添加一个 segue 和在那里添加一个 segue 很容易,但是当您有三个开发人员都在摆弄它时,管理 6 个视图和 XML 中定义的 16 个 segue 是很糟糕的。无论如何,重点是:代码给你控制,xcode生成的xml没有。
    • 我在 iOS7 中看到 [segue perform] 崩溃,不确定是否有其他人遇到这种情况。
    【解决方案4】:

    猜想这已得到回答并被接受,但我只想添加更多细节。

    我做了什么来解决一个问题,我会在第一个屏幕上显示一个登录视图,然后如果登录正确,我想继续使用应用程序。我创建了从登录视图控制器到根视图控制器的 segue,并给它一个标识符,如“myidentifier”。

    然后在检查所有登录代码后,如果登录正确,我会打电话给

    [self performSegueWithIdentifier: @"myidentifier" sender: self];
    

    我最大的误解是我试图把 segue 放在一个按钮上,一旦找到它就打断它。

    【讨论】:

    • 正如我写的另一条评论:我一直在以编程方式创建和执行自定义转场(请参阅我的答案)。
    【解决方案5】:

    您必须将您的代码链接到您正在使用的UIStoryboard。确保您进入UIStoryboard 中的YourViewController,单击它周围的边框,然后将其identifier 字段设置为您在代码中调用的NSString

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" 
                                                         bundle:nil];
    YourViewController *yourViewController = 
     (YourViewController *)
      [storyboard instantiateViewControllerWithIdentifier:@"yourViewControllerID"];
    [self.navigationController pushViewController:yourViewController animated:YES];
    

    【讨论】:

    • 我明白了,但是如果我要呈现的 viewController 嵌入在故事板的 NavigationController 中怎么办?据我所知,我可以初始化 NavigationController 以将其嵌入其中,但在情节提要中,我已经为需要呈现的视图设置了 push segues。
    • 你能详细说明一下吗?我认为这是我遇到的问题,但似乎找不到如何/在哪里执行此操作...
    • 即使这个解决方案是正确的,也是为了避免任何转场,但问题是转场。通过这种方式,您可以在两个场景之间连接或进行过渡,而无需在情节提要中进行转场。
    【解决方案6】:

    适用于情节提要中的控制器。

    jhilgert00 这是您要找的吗?

    -(IBAction)nav_goHome:(id)sender {
    UIViewController *myController = [self.storyboard instantiateViewControllerWithIdentifier:@"HomeController"];
    [self.navigationController pushViewController: myController animated:YES];
    
    }
    

    或者...

    [self performSegueWithIdentifier:@"loginMainSegue" sender:self];
    

    【讨论】:

      【解决方案7】:

      好吧,您可以创建 UIStoryBoardSegue 也可以将其子类化。子类化主要用于提供自定义过渡动画。

      您可以观看 wwdc 2011 介绍 StoryBoard 的视频。它也可以在 youtube 上找到。

      http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIStoryboardSegue_Class/Reference/Reference.html#//apple_ref/occ/cl/UIStoryboardSegue

      【讨论】:

        【解决方案8】:

        我想澄清一下...

        一个常见的误解,事实上我有一段时间了,故事板转场是由prepareForSegue:sender: 方法触发的。它不是。无论您是否为该(离开)视图控制器实现了prepareForSegue:sender: 方法,都会执行情节提要。

        我从 Paul Hegarty 出色的 iTunesU lectures 中学到了这一点。我很抱歉,但遗憾的是不记得是哪一堂课了。

        如果您在故事板中的两个视图控制器之间连接一个转场,但没有实现prepareForSegue:sender: 方法,则转场仍将转场到目标视图控制器。然而,它会继续未准备好的视图控制器。

        希望这会有所帮助。

        【讨论】:

          【解决方案9】:

          故事板转场不能在故事板之外创建。尽管有缺点,您仍需要将其连接起来。

          UIStoryboardSegue Reference 明确指出:

          您不直接创建 segue 对象。相反,故事板 运行时在必须在两个视图之间执行转场时创建它们 控制器。您仍然可以使用 performSegueWithIdentifier:sender: UIViewController 的方法,如果你 想。您可以这样做以从已添加的源启动 segue 以编程方式,因此在 Interface Builder 中不可用。

          您仍然可以使用 presentModalViewController:pushViewController:animated: 调用以编程方式告诉故事板呈现视图控制器,但您需要故事板实例。

          您可以调用UIStoryboards 类方法来获取一个命名故事板,其中主包的包为零。

          storyboardWithName:bundle:

          【讨论】:

            【解决方案10】:

            首先,假设您在故事板中有两个不同的视图,并且您想从一个屏幕导航到另一个屏幕,因此请按照以下步骤操作:

            1)。在身份检查器中使用类文件和情节提要 ID 定义您的所有视图。

            2)。确保将导航控制器添加到第一个视图。在 Storyboard 中选择它,然后选择 Editor >Embed In > Navigation Controller

            3)。在您的第一堂课中,导入“secondClass.h”

            #import "ViewController.h
            #import "secondController.h"
            

            4)。在必须执行 segue 的 IBAction 中添加此命令

            secondController *next=[self.storyboard instantiateViewControllerWithIdentifier:@"second"];
            [self.navigationController pushViewController:next animated:YES];
            

            5)。 @"second" 是 secondview 控制器类,storyboard id。

            【讨论】:

            • self.storyboard 应该是:UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
            • @masipcat 和故事板名称可能取决于您如何设置 Xcode 项目,在我的项目中它是“Main.storyboard”,所以我使用了storyboardWithName:@"Main"
            • @sanket-chauhan 如果您的第一个控制器没有嵌入到导航控制器中,您还可以使用[self showDetailViewController:next sender:self];[self showViewController:next sender:self]; 显示下一个视图
            【解决方案11】:

            我对 UIStoryboard 的 segues 进行了逆向工程并进行了开源(重新)实现:https://github.com/acoomans/Segway

            使用该库,您可以以编程方式定义转场(无需任何情节提要)。

            希望对您有所帮助。

            【讨论】:

              【解决方案12】:

              实际上有几个问题:

              首先,在您为我们上传的那个项目中,segue 不带有“segue1”标识符:

              没有标识符

              如果您尚未填写该标识符,则应填写该标识符。

              其次,当您从表视图推送到表视图时,您正在调用 initWithNibName 来创建视图控制器。你真的很想使用 instantiateViewControllerWithIdentifier。

              【讨论】:

                【解决方案13】:

                这是Creating a segue programmatically的代码示例:

                class ViewController: UIViewController {
                    ...
                    // 1. Define the Segue
                    private var commonSegue: UIStoryboardSegue!
                    ...
                    override func viewDidLoad() {
                        ...
                        // 2. Initialize the Segue
                        self.commonSegue = UIStoryboardSegue(identifier: "CommonSegue", source: ..., destination: ...) {
                            self.commonSegue.source.showDetailViewController(self.commonSegue.destination, sender: self)
                        }
                        ...
                    }
                    ...
                    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
                        // 4. Prepare to perform the Segue
                        if self.commonSegue == segue {
                            ...
                        }
                        ...
                    }
                    ...
                    func actionFunction() {
                        // 3. Perform the Segue
                        self.prepare(for: self.commonSegue, sender: self)
                        self.commonSegue.perform()
                    }
                    ...
                }
                

                【讨论】:

                • 您正在从您的操作方法调用self.prepare(for: self.commonSegue, sender: self)。那么在prepare(for:sender)方法中比较if self.commonSegue == segue {...}有什么意义呢?
                • @nayem:在prepare(for:sender:) 中,您可以在显示目标视图控制器之前对其进行配置。当然你也可以在actionFunction.
                • @nayem:我这样做的原因是试图与其他segues的处理保持一致。
                猜你喜欢
                • 2018-09-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-12-14
                • 2017-10-03
                • 1970-01-01
                相关资源
                最近更新 更多