动画替换UISplitViewController中的详细信息视图



我有一个情节提要设置,在某个时刻,一个按钮会用另一个按钮替换"详细信息视图"。默认情况下,根本没有转换:视图控制器会突然被替换。我可以创建一个吗?如何创建?

我的猜测是使用自定义转换——就像通常为视图更改使用自定义动画一样——但我不知道如何实现拆分视图控制器的"替换"行为。

我使用自定义segue完成了这项工作,当有splitViewController时,我会"显示细节",否则我会尝试推送/呈现模态。所有动画。显示模式动画将使用变换淡出旧控制器,并使用变换更改显示新控制器

class ShowDetailSegue: UIStoryboardSegue {
    private let showFromScale : CGFloat = 0.8
    private let hideToScale : CGFloat = 1.2
    private let animationDuration : NSTimeInterval = 0.33
    override func perform() {
        let sourceVC = self.sourceViewController as! UIViewController
        let destinationVC = self.destinationViewController as! UIViewController
        let animated = true
        if let splitVC = sourceVC.splitViewController where splitVC.isInSplitView {
            // splitview with detail is visible, we will show detail with animation
            showDetail(splitVC, sourceVC : sourceVC, destinationVC: destinationVC, animated: animated)
        } else if let navController = sourceVC.navigationController {
            // there is no split view – just push to navigation controller
            sourceVC.navigationController?.pushViewController(destinationVC, animated: animated)
        } else {
            // no navigation found, let just present modal
            sourceVC.presentViewController(destinationVC, animated: animated, completion: nil)
        }
    }
    private func showDetail(splitVC : UISplitViewController, sourceVC : UIViewController, destinationVC : UIViewController, animated : Bool) {
        let newDetailVC = GeneralNavigationController(rootViewController: destinationVC)
        newDetailVC.applyAppearance()
        if !animated {
            splitVC.showDetailViewController(newDetailVC, sender: sourceVC)
        } else {
            var currentDetailVC = splitVC.viewControllers.last as! UIViewController
            if let currentDetailNC = currentDetailVC as? UINavigationController {
                currentDetailVC = currentDetailNC.topViewController
            }
            UIView.animateWithDuration(animationDuration / 2.0, animations: { () -> Void in
                // hide the old view with transform
                currentDetailVC.view.alpha = 0
                currentDetailVC.view.transform = CGAffineTransformMakeScale(self.hideToScale, self.hideToScale)
                currentDetailVC.navigationController?.navigationBar.alpha = 0
                }, completion: { (completed) -> Void in
                    newDetailVC.navigationController?.navigationBar.alpha = 0
                    newDetailVC.view.alpha = 0
                    newDetailVC.view.transform = CGAffineTransformScale(newDetailVC.view.transform, self.showFromScale, self.showFromScale)
                    splitVC.showDetailViewController(newDetailVC, sender: sourceVC)
                    // Show new view
                    UIView.animateWithDuration(self.animationDuration / 2.0, animations: { () -> Void in
                        newDetailVC.view.alpha = 1
                        newDetailVC.view.transform = CGAffineTransformScale(newDetailVC.view.transform, 1 / self.showFromScale, 1 / self.showFromScale)
                        newDetailVC.navigationController?.navigationBar.alpha = 1
                        }, completion: { (completed) -> Void in
                            currentDetailVC.view.transform = CGAffineTransformScale(currentDetailVC.view.transform, 1 / self.hideToScale, 1 / self.hideToScale)
                    })
            })

        }

    }
}

我使用了Pavel Smejkal的答案,并添加了以下修饰:

  • 新的细节控制器可能已经嵌入UINavigationController,所以我检查一下
  • 我去掉了他的风俗导航控制器类
  • 我把它转换成Swift 3

这是修改后的代码:

import UIKit
class SegueShowDetail: UIStoryboardSegue {
    private let showFromScale: CGFloat = 0.8
    private let hideToScale: CGFloat = 1.2
    private let animationDuration: TimeInterval = 0.33
    override func perform() {
        let sourceVC = self.source 
        let destinationVC = self.destination 
        let animated = true
        if let splitVC = sourceVC.splitViewController, !splitVC.isCollapsed {
            // splitview with detail is visible, we will show detail with animation
            showDetail( splitVC: splitVC, sourceVC : sourceVC, destinationVC: destinationVC, animated: animated )
        } else if let navController = sourceVC.navigationController {
            // there is no split view – just push to navigation controller
            sourceVC.navigationController?.pushViewController( destinationVC, animated: animated )
        } else {
            // no navigation found, let just present modal
            sourceVC.present( destinationVC, animated: animated, completion: nil )
        }
    }
    fileprivate func showDetail( splitVC : UISplitViewController, sourceVC : UIViewController, destinationVC : UIViewController, animated : Bool ) {
        var navController: UINavigationController? = destinationVC as? UINavigationController
        if nil == navController {
            navController = UINavigationController( rootViewController: destinationVC )
        }
        guard let newDetailNavVC = navController else {
            return
        }
        if !animated {
            splitVC.showDetailViewController( newDetailNavVC, sender: sourceVC )
        } else {
            var currentDetailVC = splitVC.viewControllers.last!
            if let currentDetailNC = currentDetailVC as? UINavigationController {
                currentDetailVC = currentDetailNC.topViewController!
            }
            UIView.animate(withDuration: animationDuration / 2.0, animations: { () -> Void in
                // hide the old view with transform
                currentDetailVC.view.alpha = 0
                currentDetailVC.view.transform = CGAffineTransform(scaleX: self.hideToScale, y: self.hideToScale)
                currentDetailVC.navigationController?.navigationBar.alpha = 0
            }, completion: { (completed) -> Void in
                newDetailNavVC.navigationController?.navigationBar.alpha = 0
                newDetailNavVC.view.alpha = 0
                newDetailNavVC.view.transform = newDetailNavVC.view.transform.scaledBy( x: self.showFromScale, y: self.showFromScale )
                splitVC.showDetailViewController( newDetailNavVC, sender: sourceVC)
                // Show new view
                UIView.animate( withDuration: self.animationDuration / 2.0, animations: { () -> Void in
                    newDetailNavVC.view.alpha = 1
                    newDetailNavVC.view.transform = newDetailNavVC.view.transform.scaledBy( x: 1 / self.showFromScale, y: 1 / self.showFromScale )
                    newDetailNavVC.navigationController?.navigationBar.alpha = 1
                }, completion: { (completed) -> Void in
                    currentDetailVC.view.transform = currentDetailVC.view.transform.scaledBy( x: 1 / self.hideToScale, y: 1 / self.hideToScale)
                })
            })
        }
    }
}

相关内容

最新更新