Ios 如何通过自定义转换在当前上下文上呈现视图控制器?
我遇到了视图控制器包含的问题,希望通过自定义演示/动画“在当前上下文中”显示视图控制器 我有一个根视图控制器,它有两个子视图控制器,可以作为根视图的子视图添加和删除。当这些子视图控制器呈现视图控制器时,我希望呈现在当前上下文之上,以便当呈现的子视图从视图继承者权限中删除并取消分配时,呈现的模式也将被删除。此外,如果子A显示视图控制器,我希望在“过当前上下文”显示中,即使A仍在显示,子B的“presentedViewController”属性也为零 当我将显示的视图控制器的Ios 如何通过自定义转换在当前上下文上呈现视图控制器?,ios,swift,cocoa-touch,uikit,Ios,Swift,Cocoa Touch,Uikit,我遇到了视图控制器包含的问题,希望通过自定义演示/动画“在当前上下文中”显示视图控制器 我有一个根视图控制器,它有两个子视图控制器,可以作为根视图的子视图添加和删除。当这些子视图控制器呈现视图控制器时,我希望呈现在当前上下文之上,以便当呈现的子视图从视图继承者权限中删除并取消分配时,呈现的模式也将被删除。此外,如果子A显示视图控制器,我希望在“过当前上下文”显示中,即使A仍在显示,子B的“presentedViewController”属性也为零 当我将显示的视图控制器的modalPresent
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)
}
}
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
的动画很容易,但我认为您无法有效地更改演示控制器。可能与此处的讨论有关:注意他如何指出自定义演示控件