这是我的自定义搜索代码
class FlipFromRightSegue: UIStoryboardSegue {
override func perform() {
let source:UIViewController = self.sourceViewController as UIViewController
let destination:UIViewController = self.destinationViewController as UIViewController
UIView.transitionWithView(source.view, duration: 1.0, options: .CurveEaseInOut | .TransitionFlipFromRight, animations: { () -> Void in
source.view.addSubview(destination.view)
}) { (finished) -> Void in
destination.view.removeFromSuperview()
source.presentViewController(destination, animated: false, completion: nil)
}
}
}
我认为这样可行,但实际上只有在已执行segue时视图才会更改。当“翻转”位于中间时,我该怎么做才能使视图发生变化?
提前致谢。
答案 0 :(得分:21)
从iOS 7开始,我们通常不使用自定义segue为转换设置动画。我们要么使用标准模态演示文稿,指定modalTransitionStyle
(即我们可以为模态过渡选择的几个动画的固定列表),要么实现自定义动画过渡。这两个描述如下:
如果您只是展示另一个视图控制器的视图,将动画更改为翻转的简单解决方案是在目标视图控制器中设置modalTransitionStyle
。您可以在segue的属性下完全在Interface Builder中完成此操作。
如果你想以编程方式进行,在目标控制器中你可以在Swift 3中执行以下操作:
override func viewDidLoad() {
super.viewDidLoad()
modalTransitionStyle = .flipHorizontal // use `.FlipHorizontal` in Swift 2
}
然后,当您拨打show
/ showViewController
或present
/ presentViewController
时,您的演示文稿将以水平翻转方式执行。并且,当您关闭视图控制器时,动画会自动反转。
如果您需要更多控制,在iOS 7及更高版本中,您将使用自定义动画过渡,您可以在其中指定modalPresentationStyle
.custom
。例如,在Swift 3中:
class SecondViewController: UIViewController {
let customTransitionDelegate = TransitioningDelegate()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
modalPresentationStyle = .custom // use `.Custom` in Swift 2
transitioningDelegate = customTransitionDelegate
}
...
}
指定将实例化动画控制器的UIViewControllerTransitioningDelegate
。例如,在Swift 3中:
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return AnimationController(transitionType: .presenting)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return AnimationController(transitionType: .dismissing)
}
}
动画控制器只是.transitionFlipFromRight
是一个演示文稿,或.transitionFlipFromLeft
如果在Swift 3中解雇:
class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {
enum TransitionType {
case presenting
case dismissing
}
var animationTransitionOptions: UIViewAnimationOptions
init(transitionType: TransitionType) {
switch transitionType {
case .presenting:
animationTransitionOptions = .transitionFlipFromRight
case .dismissing:
animationTransitionOptions = .transitionFlipFromLeft
}
super.init()
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
//let inView = transitionContext.containerView
let toView = transitionContext.viewController(forKey: .to)?.view
let fromView = transitionContext.viewController(forKey: .from)?.view
UIView.transition(from: fromView!, to: toView!, duration: transitionDuration(using: transitionContext), options: animationTransitionOptions.union(.curveEaseInOut)) { finished in
transitionContext.completeTransition(true)
}
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 1.0
}
}
有关iOS 7中引入的自定义转换的详细信息,请参阅WWDC 2013视频Custom Transitions Using View Controllers。
如果应该承认上述AnimationController
实际上是过度简化,因为我们正在使用transform(from:to:...)
。这会导致动画无法取消(如果您正在使用交互式转换)。它也删除了“从”视图本身,从iOS 8开始,现在它实际上是演示控制器的工作。
所以,你真的想用UIView.animate
API做翻转动画。我很抱歉,因为以下内容涉及在关键帧动画中使用一些不直观的CATransform3D
,但它会产生一个翻转动画,然后可以进行可取消的交互式过渡。
所以,在Swift 3中:
class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {
enum TransitionType {
case presenting
case dismissing
}
let transitionType: TransitionType
init(transitionType: TransitionType) {
self.transitionType = transitionType
super.init()
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let inView = transitionContext.containerView
let toView = transitionContext.view(forKey: .to)!
let fromView = transitionContext.view(forKey: .from)!
var frame = inView.bounds
func flipTransform(angle: CGFloat, offset: CGFloat = 0) -> CATransform3D {
var transform = CATransform3DMakeTranslation(offset, 0, 0)
transform.m34 = -1.0 / 1600
transform = CATransform3DRotate(transform, angle, 0, 1, 0)
return transform
}
toView.frame = inView.bounds
toView.alpha = 0
let transformFromStart: CATransform3D
let transformFromEnd: CATransform3D
let transformFromMiddle: CATransform3D
let transformToStart: CATransform3D
let transformToMiddle: CATransform3D
let transformToEnd: CATransform3D
switch transitionType {
case .presenting:
transformFromStart = flipTransform(angle: 0, offset: inView.bounds.size.width / 2)
transformFromEnd = flipTransform(angle: -.pi, offset: inView.bounds.size.width / 2)
transformFromMiddle = flipTransform(angle: -.pi / 2)
transformToStart = flipTransform(angle: .pi, offset: -inView.bounds.size.width / 2)
transformToMiddle = flipTransform(angle: .pi / 2)
transformToEnd = flipTransform(angle: 0, offset: -inView.bounds.size.width / 2)
toView.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
fromView.layer.anchorPoint = CGPoint(x: 1, y: 0.5)
case .dismissing:
transformFromStart = flipTransform(angle: 0, offset: -inView.bounds.size.width / 2)
transformFromEnd = flipTransform(angle: .pi, offset: -inView.bounds.size.width / 2)
transformFromMiddle = flipTransform(angle: .pi / 2)
transformToStart = flipTransform(angle: -.pi, offset: inView.bounds.size.width / 2)
transformToMiddle = flipTransform(angle: -.pi / 2)
transformToEnd = flipTransform(angle: 0, offset: inView.bounds.size.width / 2)
toView.layer.anchorPoint = CGPoint(x: 1, y: 0.5)
fromView.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
}
toView.layer.transform = transformToStart
fromView.layer.transform = transformFromStart
inView.addSubview(toView)
UIView.animateKeyframes(withDuration: self.transitionDuration(using: transitionContext), delay: 0, options: [], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.0) {
toView.alpha = 0
fromView.alpha = 1
}
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
toView.layer.transform = transformToMiddle
fromView.layer.transform = transformFromMiddle
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.0) {
toView.alpha = 1
fromView.alpha = 0
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
toView.layer.transform = transformToEnd
fromView.layer.transform = transformFromEnd
}
}, completion: { finished in
toView.layer.transform = CATransform3DIdentity
fromView.layer.transform = CATransform3DIdentity
toView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
fromView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 1.0
}
}
仅供参考,iOS 8使用演示控制器扩展了自定义转换模型。有关详细信息,请参阅WWDC 2014视频A Look Inside Presentation Controllers。
无论如何,如果在转换结束时,“from”视图不再可见,您将指示您的演示控制器将其从视图层次结构中删除,例如:
class PresentationController: UIPresentationController {
override var shouldRemovePresentersView: Bool { return true }
}
显然,您必须通知此演示控制器的TransitioningDelegate
:
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
...
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return PresentationController(presentedViewController: presented, presenting: presenting)
}
}
此答案已针对Swift 3进行了更新。如果您想查看Swift 2实施,请参阅previous revision of this answer。