是否可以在带有代码的滚动视图中嵌入 segue/包含视图?

Posted

技术标签:

【中文标题】是否可以在带有代码的滚动视图中嵌入 segue/包含视图?【英文标题】:Is it possible to have embed segue/containing view in a scrollview with code? 【发布时间】:2013-09-21 03:58:49 【问题描述】:

在一个 iPhone 项目中,我使用 Xcode 故事板在主滚动视图中嵌入了一些包含视图。我听说包含视图也是一种“嵌入转场”。现在我不必嵌入其他子控制器,我可以创建自定义视图并在这些自定义子视图中拥有原始子控制器的逻辑。 (我想我只是在发布到这里之后才这样做,因为它看起来更容易。)但是我已经完成了代码并且想知道保持它的难易程度。

因为滚动视图内容大于主屏幕边界,所以在故事板中布局容器视图更加困难。我可以想到三种方法来解决它。我也可以

    上下拖动滚动视图并将我的容器视图放在那里。 只需在滚动视图中拖动一些视图,然后在主控制器的 viewDidLoad 中调整框架的大小。 (如果我使用自动布局,那么我会在那里添加自动布局)但似乎违背了拥有故事板和首先嵌入 segue 的优势。但如果我必须与子视图控制器交互,它似乎比 #3 更容易。 忘记情节提要,只需编写一个包含控制器逻辑(如 WWDC 2012 视频实施 UIViewController Containment 中所述),但这似乎很复杂。

有没有办法在 Xcode 中创建嵌入转场,但不是将其放入,而是像其他视图转换一样执行“手动转场”之类的操作?我无法在故事板中看到布局,但至少它会比 #3 更容易,而且我不必像 #2 那样上下拖动,这看起来很傻。

【问题讨论】:

以编程方式创建容器视图实际上并没有那么复杂,它只是像两三行额外的代码(以编程方式创建视图)。我已经这样做了很多次(我不使用故事板)。如果在我的特定情况下有意义的话,这就是我个人会采取的路线。 您是添加视图还是视图控制器(通过 embed segue)取决于您在这些视图中执行的操作。如果不知道你想在那里做什么,很难给你建议。 @Firo 你的意思和我说的一样吗?我说的是添加子视图控制器。这是一个小时的 WWDC 视频,只是关于这个主题,不能那么容易。 =/ @rdelmar:假设我只想添加子视图控制器,这就是我的问题的目标。 我想我仍然可以按照我在故事板中的方式进行操作,我最终得到了这个解决方案:***.com/questions/16889123/… 【参考方案1】:

我知道 WWDC 上有一个小时的视频。但是,如果您看过他们的任何其他视频,就会很清楚时间与复杂性没有直接关系。这是您以编程方式使用容器(或子视图控制器)的方式:

[self addChildViewController:child];        // 1
[self.view addSubview:child.view];          // 2
[child didMoveToParentViewController:self]; // 3

与添加子视图相比,非常简单,只需多行两行代码。正如您所说,有故事板解决方案,但根据您的复杂性,通过代码执行此操作可能会更容易。不过,这真的取决于您的喜好。

如果您打算以动画方式添加视图,您应该在完成块中最后一次调用didMoveToParentViewController(即在动画完成之后)。

【讨论】:

Re: didMoveToParentViewController,来自文档:“如果你正在实现自己的容器视图控制器,它必须在转换到新控制器后调用子视图控制器的 didMoveToParentViewController: 方法,或者,如果没有过渡,则在调用 addChildViewController: 方法后立即执行。” 在拨打-addChildViewController:之前不要忘记拨打-willMoveToParentViewController: @erikprice addChildViewController: 会自动为您调用 willMoveToParentViewController:。之所以需要手动调用didMoveToParentViewController是因为你负责什么时候添加。 @Firo 哦,我误读了文档。我们必须在从自定义容器控制器中移除的子节点上调用-willMoveToParentViewController:。但是正如您所说,当我们调用-addChildViewController: 时,会为我们在添加的子对象上调用该方法。谢谢@Firo。【参考方案2】:

以下是我用来以编程方式在视图中嵌入子视图控制器的辅助函数。

struct MyChildViewController 
  static func embed(
    viewControllerId: String,
    storyboardName: String,
    containerViewController: UIViewController,
    containerView: UIView) -> UIViewController? 

    guard let viewController = initViewController(viewControllerId, storyboardName: storyboardName)
      else  return nil 

    containerViewController.addChildViewController(viewController)
    containerView.addSubview(viewController.view)

    viewController.view.translatesAutoresizingMaskIntoConstraints = false

    MyConstraints.fillParent(
      viewController.view, parentView: containerView, margin: 0, vertically: true)

    MyConstraints.fillParent(
      viewController.view, parentView: containerView, margin: 0, vertically: false)

    viewController.didMoveToParentViewController(containerViewController)

    return viewController
  

  static func initViewController(viewControllerId: String, storyboardName: String) -> UIViewController? 
    let storyboard = UIStoryboard(name: storyboardName, bundle: NSBundle.mainBundle())
    return storyboard.instantiateViewControllerWithIdentifier(viewControllerId)
  


struct MyConstraints 
  static func fillParent(view: UIView, parentView: UIView, margin: CGFloat = 0,
    vertically: Bool) -> [NSLayoutConstraint] 

    var marginFormat = ""

    if margin != 0 
      marginFormat = "-\(margin)-"
    

    var format = "|\(marginFormat)[view]\(marginFormat)|"

    if vertically 
      format = "V:" + format
    

    let constraints = NSLayoutConstraint.constraintsWithVisualFormat(format,
      options: [], metrics: nil,
      views: ["view": view])

    parentView.addConstraints(constraints)

    return constraints
  

用法:

let childWiewController = MyChildViewController.embed("MyViewControllerId", storyboardName: "MyStoryboardName", containerViewController: containerViewController, containerView: containerView)

地点:

“MyViewControllerId” - 将嵌入的子视图控制器的故事板 ID。 “MyStoryboardName” - 带有嵌入式视图控制器的故事板文件的名称。 containerView - 容器视图控制器中将嵌入子视图控制器的视图。

【讨论】:

为什么你必须自己做fillParent的事情?如果您通过情节提要使用 UIContainerView,为什么 ios 只为您执行此操作? 我想我明白了 -> childViewController.view.frame = containerView.frame 对我有用 @Arjan 在我的示例中,我以编程方式嵌入子视图控制器,而不是来自情节提要。我创建 fillParent 是为了创建布局约束。如果父大小发生变化(例如,方向改变),这将保持子大小与父大小相同。

以上是关于是否可以在带有代码的滚动视图中嵌入 segue/包含视图?的主要内容,如果未能解决你的问题,请参考以下文章

UIStoryboardSegue 嵌入

嵌入 Segue 目标视图控制器被排除在 UI 状态恢复之外

嵌入 Segue - iOS 5

使用带有分段控制的 Storyboard Segue

是否可以将带有许多包的 Python 脚本嵌入到 C# 中?

Swift 导航控制器嵌入在带有 segue 的选项卡栏中