Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何通过自定义转换在当前上下文上呈现视图控制器?_Ios_Swift_Cocoa Touch_Uikit - Fatal编程技术网

Ios 如何通过自定义转换在当前上下文上呈现视图控制器?

Ios 如何通过自定义转换在当前上下文上呈现视图控制器?,ios,swift,cocoa-touch,uikit,Ios,Swift,Cocoa Touch,Uikit,我遇到了视图控制器包含的问题,希望通过自定义演示/动画“在当前上下文中”显示视图控制器 我有一个根视图控制器,它有两个子视图控制器,可以作为根视图的子视图添加和删除。当这些子视图控制器呈现视图控制器时,我希望呈现在当前上下文之上,以便当呈现的子视图从视图继承者权限中删除并取消分配时,呈现的模式也将被删除。此外,如果子A显示视图控制器,我希望在“过当前上下文”显示中,即使A仍在显示,子B的“presentedViewController”属性也为零 当我将显示的视图控制器的modalPresent

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

我有一个根视图控制器,它有两个子视图控制器,可以作为根视图的子视图添加和删除。当这些子视图控制器呈现视图控制器时,我希望呈现在当前上下文之上,以便当呈现的子视图从视图继承者权限中删除并取消分配时,呈现的模式也将被删除。此外,如果子A显示视图控制器,我希望在“过当前上下文”显示中,即使A仍在显示,子B的“presentedViewController”属性也为零

当我将显示的视图控制器的
modalPresentationStyle
设置为
overCurrentContext
,并且如果子视图控制器的
definesPresentationContext
设置为true,则一切正常

但是,如果将
modalPresentationStyle
设置为
custom
并覆盖
shouldPresentInFullscreen
在我的自定义演示控制器中返回false,则这在我预期的情况下不起作用

下面是一个说明问题的示例:

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)
    }
}
  • 这将显示具有包含两个子视图控制器的滚动视图的ViewController
  • 左侧的红色视图控制器将显示一个进度视图控制器,该控制器应在当前上下文中显示
  • 如果视图控制器“在当前上下文中”正确显示,则可以滚动滚动视图,如果选中蓝色右侧视图控制器的“presentedViewController”属性,则该属性应为零。这些都不是真的
  • 如果将
    ProgressController
    上的
    setup()
    功能更改为:

    private func setup() {
        modalPresentationStyle = .overCurrentContext
        modalTransitionStyle = .crossDissolve
        transitioningDelegate = progressTransitioningDelegate
    }
    
    演示文稿/视图继承人权限将按预期运行,但不会使用自定义演示文稿

    苹果关于
    shouldPresentInFullscreen
    的文档似乎表明这应该是可行的:

    此方法的默认实现返回true,表示 演示文稿覆盖整个屏幕。你可以覆盖这个 方法并返回false以强制演示文稿仅在 当前环境

    如果重写此方法,请不要调用super


    我在iOS 10上的Xcode 8和iOS 11上的Xcode 9中对此进行了测试,上述代码在这两种情况下都无法正常工作。

    我猜您发现了一个bug。文档说,
    shoulldpresentinfullscreen
    可以将其转换为
    currentContext
    演示,但它没有任何作用。(除了你的测试和我的测试之外,我在网上发现了一些关于这方面的投诉,这让我认为情况就是这样。)

    结论是,如果使用
    .custom
    的表示样式,则无法获得默认的
    currentContext
    行为(其中运行时咨询源代码视图控制器并在层次结构上查找
    definesPresentationContext


    我建议向苹果公司提交一个bug。

    我还认为
    应该在fullscreen
    上做些什么。如果你问我的话,那就是一只虫子

    要解决此问题,您应该覆盖PresentedViewContainerView的框架并返回调整后的框架


    然后,重写ContainerViewillLayoutSubview并设置
    self.presentedViewController.view.frame=self.frameOfPresentedViewInContainerView
    。在这里,您还应该设置任何背景或chrome视图的框架。

    我最近也遇到了同样的问题。您是对的,UIKit文档似乎误导了UIPresentationController.shouldPresentInFullscreen的行为。但是,在尝试此属性时,我发现当它设置为“否”时,会将UITransitionView添加到窗口中,但当它设置为“是”时,会将其添加到最近显示的UIViewController的UITransitionView中。这不包括DefinePresentationContext属性返回YES的子UIViewController


    但是,如果在DefinePresentationContext==是的UIViewController上呈现UIModalPresentationStyleOverCurrentContext的UIViewController,则UIKit会在呈现视图控制器上方的层次结构中插入呈现容器视图。如果您使用UIModalPresentationStyleCustom和UIPresentationController(其shouldPresentInFullscreen属性返回NO)在呈现的UIViewController上呈现,呈现的UIViewController的表示容器视图将插入到在子UIViewController的当前上下文中呈现的第一个UIViewController中。

    可能不支持此操作,但是,如果不提供此功能,表示控制器上的
    shouldpresentfullscreen
    的目的是什么?在本例中,当文档似乎表明应该覆盖它时,覆盖它不会起任何作用。也许我感到困惑。我从
    shoulldpresentinfullscreen
    显式返回false,以将其转换为非全屏转换,但当我返回false时,其行为与当前上下文转换(或过当前上下文)不同。更改返回的内容与我对自定义演示文稿的了解完全不同。好的,我进一步研究了这一点。如果在子对象的
    definedPresentationContext
    前面放置了一个计算过的覆盖,则当表示样式为
    .custom
    时,甚至不会调用它。所以我不得不说,这个功能并不像广告宣传的那样有效。更改
    .currentContext
    的动画很容易,但我认为您无法有效地更改演示控制器。可能与此处的讨论有关:注意他如何指出自定义演示控件