【问题标题】:Reusing UIViewController for modal and non-modal situations在模态和非模态情况下重用 UIViewController
【发布时间】:2010-12-11 18:54:53
【问题描述】:

我有一个 UIViewController——我们称之为“FormController”——它只是一个编辑对象的表单。我想在两种不同的情况下使用它:

  1. 创建一个新对象——使用 UINavigationController 的 presentModalViewController: 方法。

  2. 编辑现有对象 - 将视图控制器推入 UINavigationController 堆栈,而不是使用对话框方法。

在模态情况下,我希望有一个带有“取消”和“完成”按钮的工具栏,而在堆栈情况下,我希望只有 UINavigationController 提供的导航栏。

这将类似于联系人应用程序,其中“新联系人”和“编辑联系人”屏幕似乎使用相同的视图控制器,但新联系人表单在编辑屏幕被推送到导航堆栈时以模态方式呈现.

我的问题是:处理这两种情况的最佳方法是什么,而无需编写 2 个单独但大部分相同的视图控制器?

我想过创建一个“ModalFormController”,它通过组合封装裸露的“FormController”并添加一个工具栏,但我在文档中的某处读到 Apple 不建议嵌套视图控制器。

【问题讨论】:

    标签: iphone ios cocoa-touch uiviewcontroller uinavigationcontroller


    【解决方案1】:

    为什么不使用子类化?将ModalCreateFormController 设为EditFormController 的子类,并在子类中处理特定于模态的内容。

    【讨论】:

    • 我也想过。也许下次我会尝试……我很难决定走哪条路。
    【解决方案2】:

    我所做的(有时)是设置一个enum 来指定视图控制器的类型。

    例如,您可能有两种类型:Edit 类型和 Add(“新”)类型。

    Add 类型通过模态视图控制器实现,而Edit 类型被推送到现有导航堆栈。

    在视图控制器的-viewDidLoad: 方法中,我简单地做了一个switch/case 树,它根据上面指定的类型枚举设置标题和其他外观特征。

    这样做的好处是添加新类型很容易。缺点是处理此枚举的条件树可能会很快变得复杂,具体取决于类型的不同程度。

    但是switch/case 树使它更易于管理。

    因此,这取决于您要对这两种类型进行什么操作。但这绝对是可行的。

    【讨论】:

    • 谢谢亚历克斯。我认为所有答案都是有效的,但经过深思熟虑,我将朝着您设定的方向前进。我只是要使用一个知道 FormController 是否正在模态显示的 BOOL。
    【解决方案3】:

    除了在视图控制器上有一个显式属性(正如 Alex Reynolds 建议的那样),我想到的另外两种方法是:

    1. 如果您正在编辑某种模型对象,请询问其当前状态。如果它曾经被保存过,那么你就处于编辑模式。否则,您将处于创建模式。

    2. 查看控制器的parentViewController 属性的值。如果它是UINavigationController 的实例,那么您就在导航堆栈中。如果您以模态方式显示,它将是您的列表控制器的一个实例。

    【讨论】:

    • 感谢 Sixten。我将在 #2 中结合上面 Alex 的回答使用这个想法。
    【解决方案4】:

    呃,我讨厌多余的 ivars……

    我改用这个:

    if([[self.navigationController viewControllers] objectAtIndex:0] == self){
    
            //Modal
    
        }else{
    
            //Pushed
    
        }
    

    这有点小题大做,但我们使用的逻辑是,如果有问题的视图控制器是堆栈中的第一个,则您无法返回。实际上我们完全忽略了它是否是模态显示的事实。

    【讨论】:

    • 我把它变成了 UIViewController 的一个类别: - (BOOL)isModal { return ([[self.navigationController viewControllers] objectAtIndex:0] == self); }
    • @marcelnijman 虽然我理解您对UIViewController 类别所做的尝试,但它并非在所有情况下都有效。例如,这会为您的应用的初始视图控制器返回误报,因为它位于堆栈的顶部。
    【解决方案5】:

    我不得不在我的应用程序中多次这样做,并尝试了几种不同的方法,包括模态子类和使用 forwardInvocation 的可重用模态帮助程序类。我发现最好的模式是为每个视图控制器创建一个 containsModalViewController 方法,该方法(通常)创建并返回一个 UINavigationController 供调用者与 presentModalViewController 一起使用。

    在大多数情况下,此方法构建并返回一个 UINavigationController ,其中 self 作为根视图控制器(重复调用该方法检查 self.navigationController 并在它不为零时返回它)。在其他情况下,我首先制作了一个虚拟根控制器,然后将 self 推到第二个以获得后退按钮。然后可以使用一个技巧来捕捉返回按钮按下:http://smallduck.wordpress.com/2010/10/05/intercepting-uinavigationcontroller/

    在某些情况下,视图不需要导航栏,因此此方法只是调整一些标志并返回 self。我什至发现在某些确实需要导航栏的情况下,让该方法调用 self.view,然后调整视图层次结构以添加 UINavigationBar 并再次返回 self 会更简单。但在任何情况下,设置通常与该方法隔离,并且调用者在每种情况下都以相同的方式处理它。

    【讨论】:

      【解决方案6】:

      Apple explains how the contacts application works under the hood:

      要允许自定义视图控制器类用于显示和编辑内容,请覆盖setEditing:animated: 方法。

      您可以免费获得一些功能,例如Edit/Done 按钮。

      【讨论】:

        猜你喜欢
        • 2014-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-18
        • 1970-01-01
        • 1970-01-01
        • 2017-12-22
        相关资源
        最近更新 更多