在模态视图控制器的解除动画时访问presentingViewController
Posted
技术标签:
【中文标题】在模态视图控制器的解除动画时访问presentingViewController【英文标题】:Accessing presentingViewController while dismissal animation of a Modal View Controller 【发布时间】:2017-01-25 20:28:10 【问题描述】:我在主视图控制器中有一个按钮,它以模态方式呈现另一个视图控制器。当模态vc向上滑动时,我制作了一个主视图控制器变暗的自定义动画。但是,当模态vc向下滑动(使用dismiss)时,我怎样才能让它倒退? 使用this site 上的教程,我创建了访问呈现 vc 的协议,但动画没有发生,它只是立即改变了不透明度。
另外,如果我将动画代码放入正在呈现的 vc 的 viewWillAppear 中,它只会在模态 vc 一直向下滑动(消失)时才开始动画。我没有使用常规的 show segue,因为我认为这不是摆脱模态 vc 的最佳方法。如果我错了,请纠正我
这是演示vc中的prepareForSegue
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
if let identifier = segue.identifier
switch identifier
case "showSettings":
let tempFrame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
dimView = UIView(frame: tempFrame)
dimView.backgroundColor = .black
dimView.layer.opacity = 0
self.view.addSubview(dimView)
UIView.animate(withDuration: 0.5, animations:
self.dimView.layer.opacity = 0.4
)
default:break
if let vc = segue.destination as? Dismissable
vc.dismissalDelegate = self
这是一个 IBaction,它消除了自身内部的模态 vc。
@IBAction func dismiss()
dismissalDelegate?.finishedShowing(viewController: self)
UIView.animate(withDuration: 1.0, animations:
(self.dismissalDelegate as! ViewController).dimView.layer.opacity = 0.3
)
【问题讨论】:
也许你应该通过 unwindsegue 来做到这一点。谷歌一下,你会找到一些相关的教程。 感谢您的帮助,我设法使用 unwindSegue 回到演示 VC(对我来说是新技术,非常方便,谢谢 :D),但动画仍然没有发生,它不断变化呈现的 vc 视图在出现之前的不透明度。 诀窍是生成呈现 VC 的屏幕截图,并将其用作呈现 VC 的背景。然后你用那个图像做任何你想要的动画。然后,当你的动画完成后,你的展开看起来就完成了,所以你可以直接弹出没有动画的 VC。 哇,有没有办法以编程方式生成屏幕截图?我真的很怀疑,这里有一个问题,我应该如何为所有设备优化它?我现在拥有的解决方案看起来并不像预期的那样,但很接近,而且我不确定是否值得使用这个技巧。我通过委托访问呈现 vc,将其不透明度更改为 0.3,并在其 viewWillAppear 中在 0.5 秒内将其更改为 0。这几乎是好的 :D 我想我最好专注于我笨拙的应用程序的更重要的功能 为您添加一些示例代码的答案。不知道是 swift 2 还是 3,但它应该给你一些指示 【参考方案1】:这只是如何完成的一个示例。很确定它远非完美,但应该作为一个起点。那里有很多特定于我的旧项目的代码,但可以删除。
final class ModalSeguePushStyle : UIStoryboardSegue
override func perform()
let sourceVC = self.sourceViewController
let destinationVC = self.destinationViewController
var endPosition = destinationVC.view.frame
var startPostition = destinationVC.view.frame
startPostition.origin.x = startPostition.width
if sourceVC.navigationController != nil
startPostition.origin.y = -44
endPosition.origin.y = -44
destinationVC.view.frame = startPostition
sourceVC.view.addSubview(destinationVC.view)
UIView.animateWithDuration(0.3, animations: () -> Void in
destinationVC.view.frame = endPosition
) (Bool) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController, animated: false, completion: nil)
final class ModalSeguePushStyleUnwind : UIStoryboardSegue
func createMockView(view: UIView) -> UIImageView
UIGraphicsBeginImageContextWithOptions(view.frame.size, true, UIScreen.mainScreen().scale)
view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return UIImageView(image: image)
override func perform()
let sourceVC = self.sourceViewController
let destinationVC = self.destinationViewController
var endPosition = sourceVC.view.frame
endPosition.origin.x += endPosition.width
var bar:UIImageView?
let mock = createMockView(destinationVC.view)
if destinationVC.navigationController != nil
mock.frame.origin.y = 64
sourceVC.view.superview!.insertSubview(mock, atIndex: 0)
if let b = destinationVC.tabBarController?.tabBar
bar = createMockView(b)
bar?.frame = b.frame
sourceVC.view.superview!.insertSubview(bar!, aboveSubview: mock)
UIView.animateWithDuration(0.3, animations: () -> Void in
sourceVC.view.frame = endPosition
) (Bool) -> Void in
sourceVC.dismissViewControllerAnimated(false, completion: () -> Void in
)
【讨论】:
以上是关于在模态视图控制器的解除动画时访问presentingViewController的主要内容,如果未能解决你的问题,请参考以下文章
为啥在模态视图控制器被解除后 CAGradientLayer 从视图中删除