如何通过自定义转换呈现当前上下文的视图控制器? [英] How do I present a view controller over current context with a custom transition?

查看:52
本文介绍了如何通过自定义转换呈现当前上下文的视图控制器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了视图控制器包含问题,并希望通过自定义演示/动画在当前上下文中显示视图控制器。

I am running into a problem with view controller containment and wanting to present view controllers "over current context" with a custom presentation/animation.

我有一个root具有两个子视图控制器的视图控制器,可以将两个子视图控制器作为子视图控制器添加到根中。当这些子视图控制器呈现一个视图控制器时,我希望该呈现在当前上下文上进行,以便在从视图层次结构中移除所呈现的子代并重新分配所呈现的模态时也将被移除。另外,如果子项A呈现了一个视图控制器,我希望子项B的 presentedViewController属性在在当前上下文中呈现中为零,即使A仍在呈现。

I have a root view controller that has two child view controllers that can be added and removed as children to the root. When these child view controllers present a view controller I want the presentation to be over current context so that when the child that is presenting is removed from the view heirarchy and deallocated the presented modal will be removed as well. Also, if child A presents a view controller, I would expect child B's 'presentedViewController' property to be nil in an "over current context" presentation even if A was still presenting.

当我将显示的视图控制器的 modalPresentationStyle 设置为 overCurrentContext时,一切都会按预期进行,如果子视图控制器将 definesPresentationContext 设置为true。

Everything works as expected when I set the modalPresentationStyle of my presented view controller to overCurrentContext, and if the child view controllers have definesPresentationContext set to true.

无法正常工作,但是如果将 modalPresentationStyle 设置为 custom 并覆盖 shouldPresentInFullscreen 在我的自定义表示控制器中返回false。

This doesn't work when I would expect it to however if I have modalPresentationStyle set to custom and override shouldPresentInFullscreen returning false in my custom presentation controller.

以下是说明问题的示例:

Here is an example illustrating the problem:

import UIKit

final class ProgressController: UIViewController {
    private lazy var activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .white)
    private lazy var progressTransitioningDelegate = ProgressTransitioningDelegate()

    // MARK: Lifecycle

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

        setup()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        setup()
    }

    override public func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(white: 0, alpha: 0)

        view.addSubview(activityIndicatorView)
        activityIndicatorView.startAnimating()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    override public func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        activityIndicatorView.center = CGPoint(x: view.bounds.width/2, y: view.bounds.height/2)
    }

    // MARK: Private

    private func setup() {
        modalPresentationStyle = .custom
        modalTransitionStyle = .crossDissolve
        transitioningDelegate = progressTransitioningDelegate
    }
}

final class ProgressTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        return DimBackgroundPresentationController(presentedViewController: presented, presenting: source)
    }
}

final class DimBackgroundPresentationController: UIPresentationController {
    lazy var overlayView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0, alpha: 0.5)
        return v
    }()

    override var shouldPresentInFullscreen: Bool {
        return false
    }

    override func presentationTransitionWillBegin() {
        super.presentationTransitionWillBegin()

        overlayView.alpha = 0
        containerView!.addSubview(overlayView)
        containerView!.addSubview(presentedView!)

        if let coordinator = presentedViewController.transitionCoordinator {
            coordinator.animate(alongsideTransition: { _ in
                self.overlayView.alpha = 1
            }, completion: nil)
        }
    }

    override func containerViewDidLayoutSubviews() {
        super.containerViewDidLayoutSubviews()

        overlayView.frame = presentingViewController.view.bounds
    }

    override func dismissalTransitionWillBegin() {
        super.dismissalTransitionWillBegin()

        let coordinator = presentedViewController.transitionCoordinator
        coordinator?.animate(alongsideTransition: { _ in
            self.overlayView.alpha = 0
        }, completion: nil)
    }
}

class ViewControllerA: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        definesPresentationContext = true

        let vc = ProgressController()
        self.present(vc, animated: true) {
        }
    }
}

class ViewController: UIViewController {

    let container = UIScrollView()

    override func viewDidLoad() {
        super.viewDidLoad()

        container.frame = view.bounds
        view.addSubview(container)

        let lhs = ViewControllerA()
        lhs.view.backgroundColor = .red

        let rhs = UIViewController()
        rhs.view.backgroundColor = .blue

        addChildViewController(lhs)
        lhs.view.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height)
        container.addSubview(lhs.view)
        lhs.didMove(toParentViewController: self)

        addChildViewController(rhs)
        rhs.view.frame = CGRect(x: view.bounds.width, y: 0, width: view.bounds.width, height: view.bounds.height)
        container.addSubview(rhs.view)
        rhs.didMove(toParentViewController: self)


        container.contentSize = CGSize(width: view.bounds.width * 2, height: view.bounds.height)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
//        let rect = CGRect(x: floor(view.bounds.width/2.0), y: 0, width: view.bounds.width, height: view.bounds.height)
//        container.scrollRectToVisible(rect, animated: true)
    }
}




  1. 这将显示一个ViewController,其滚动视图包含两个子视图控制器

  2. 左侧的红色视图控制器将显示一个进度视图控制器,该视图控制器应在当前上下文中显示。

  3. 如果视图控制器被正确呈现,在当前上下文中,则可以滚动滚动视图,并且如果选中了蓝色右侧视图控制器的 presentedViewController属性,则该属性应为nil。

如果更改 setup()函数在 ProgressController 上:

private func setup() {
    modalPresentationStyle = .overCurrentContext
    modalTransitionStyle = .crossDissolve
    transitioningDelegate = progressTransitioningDelegate
}

演示文稿/视图的层次结构将按预期方式运行,但不会使用自定义演示文稿。

the presentation/view heirarchy will behave as expected, but the custom presentation will not be used.

Apple文档中的 shouldPresentInFullscreen 似乎表明这应该起作用:

Apple's docs for shouldPresentInFullscreen seem to indicate that this should work:


此方法的默认实现返回true,表示
演示文稿覆盖了整个屏幕。您可以覆盖此
方法并返回false,以强制演示文稿仅在
当前上下文中显示。

The default implementation of this method returns true, indicating that the presentation covers the entire screen. You can override this method and return false to force the presentation to display only in the current context.

如果覆盖此方法,请执行

If you override this method, do not call super.

我在iOS 10的Xcode 8和iOS 11的Xcode 9上对此进行了测试,上面的代码无法正常工作

I tested this in Xcode 8 on iOS 10 and Xcode 9 on iOS 11 and the above code would not work as expected in either case.

推荐答案

我猜你发现了一个错误。文档说 shouldPresentInFullscreen 可以将其转换为 currentContext 演示文稿,但它什么也没做。 (除了您的测验和我的测验,我还在网上发现了一些投诉,导致我认为是这种情况。)

I'm going to guess that you've found a bug. The docs say that shouldPresentInFullscreen can turn this into a currentContext presentation, but it does nothing. (In addition to your test and my test, I found a few online complaints about this, leading me to think that that's the case.)

结论是您不能如果您获得默认的 currentContext 行为(运行时在其中查询源视图控制器并向上层次结构查找 definesPresentationContext )使用演示样式为 .custom

The conclusion is that you cannot get the default currentContext behavior (where the runtime consults the source view controller and up the hierarchy looking for definesPresentationContext) if you use presentation style of .custom.

我建议向Apple提交错误。

I suggest filing a bug with Apple.

这篇关于如何通过自定义转换呈现当前上下文的视图控制器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆