iOS Swift:自定义交互式转换

问题描述 投票:0回答:2

我写了一个自定义滑动过渡,在模态演示文稿中工作正常。但在推送演示中,“到”视图位置不是动画。

我尝试了相同的代码,用alpha切换翻译,它的工作原理。

从视图完美运行,它只是在动画期间保持固定的视图。

func transitionAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating {
    let duration = transitionDuration(using: transitionContext)
    let container = transitionContext.containerView

    let toController = transitionContext.viewController(forKey: .to)
    toController?.beginAppearanceTransition(true, animated: true)

    guard
    let to = transitionContext.view(forKey: .to),
    let from = transitionContext.view(forKey: .from)
        else {
        print("To or from view are nil!")
        fatalError()
    }

    container.addSubview(to)

    let animator = UIViewPropertyAnimator(duration: duration, curve: .linear)
    var toStartingPoint: CGPoint
    var fromEndingPoint: CGPoint

    switch self.from {
    case .down:
        toStartingPoint = CGPoint(x: 0, y: -from.bounds.height)
        fromEndingPoint = CGPoint(x: 0, y: from.bounds.height)
    case .top:
        toStartingPoint = CGPoint(x: 0, y: from.bounds.height)
        fromEndingPoint = CGPoint(x: 0, y: -from.bounds.height)
    case .right:
        toStartingPoint = CGPoint(x: from.bounds.width, y: 0)
        fromEndingPoint = CGPoint(x: -from.bounds.width, y: 0)
    case .left:
        toStartingPoint = CGPoint(x: -from.bounds.width, y: 0)
        fromEndingPoint = CGPoint(x: from.bounds.width, y: 0)
    }

    to.transform = CGAffineTransform(translationX: toStartingPoint.x, y: toStartingPoint.y)

    animator.addAnimations({
        from.transform = CGAffineTransform(translationX: fromEndingPoint.x, y: fromEndingPoint.y)
    }, delayFactor: 0.0)

    animator.addAnimations({
        to.transform = .identity
    }, delayFactor: 0.0)


    animator.addCompletion { [weak self] position in
        switch position {
        case .start:
            self?.auxCancelCompletion?()
            transitionContext.completeTransition(false)
            self?.auxAnimationsCancel?()
        case .end:
            self?.auxEndCompletion?()
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
            from.transform = .identity
            to.transform = .identity
        default:
            transitionContext.completeTransition(false)
            self?.auxAnimationsCancel?()
        }
    }

    if let auxAnimations = auxAnimations {
        animator.addAnimations(auxAnimations)
    }

    self.animator = animator
    self.context = transitionContext

    animator.addCompletion { [unowned self] _ in
        self.animator = nil
        self.context = nil
    }
    animator.isUserInteractionEnabled = true

    return animator
}

我认为这是代理问题,但navigationDelgate设置正确,否则我想我不会看到任何动画..

代表设置:

override func viewDidLoad() {
    super.viewDidLoad()
    transitionHelper = SwipeInteractiveTransitionHelper(withDelegate: self)
}


extension TodayViewController: UINavigationControllerDelegate {

    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return transitionHelper?.swipeTransition
    }

    func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return transitionHelper?.swipeTransition
    }
}

这是自定义推送协调器,其中viewController是下一个视图控制器,我附加委托的位置。

    case .pushCustom:
        guard let navigationController = currentViewController.navigationController else {
            fatalError("Can't push a view controller without a current navigation controller")
        }
        guard let current = currentViewController as? UINavigationControllerDelegate else {
            fatalError("Can't push a view controller without a current  navigation delegate")
        }
        navigationController.delegate = current
        navigationController.pushViewController(viewController, animated: true) { [weak self] in
            self?.currentViewController = SceneCoordinator.actualViewController(for: viewController)
            completion?()
        }
ios swift uiviewanimationtransition
2个回答
0
投票

解决了为目标视图设置快照的动画,而不是直接设置目标视图的动画。

let to = transitionContext.view(forKey:.to)let toViewSnapshot = to.snapshotView(afterScreenUpdates:true)

只需使用toViewSnapshot作为动画即可


0
投票

我这样做的是什么。希望它会对你有所帮助。

VC:UIViewController
{
@IBAction func test(_ sender: Any){
navigationController?.delegate = self
let destine = storyboard?.instantiateViewController(withIdentifier: "target")
navigationController?.pushViewController(destine!, animated: true)
}

  func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?{
    return Traistion()
}

}


 class Traistion:  NSObject, UIViewControllerAnimatedTransitioning{


func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let animator  = transitionAnimator(using: transitionContext)
    animator.startAnimation()
}

var animator: UIViewPropertyAnimator!
var context: UIViewControllerContextTransitioning!

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval{
    return 1.0
}

enum Direction {
    case down
    case top
    case left
    case right
}

var from : Direction = .left

var auxCancelCompletion :(()->())? = {
    return nil
}()

var auxAnimationsCancel :(()->())? = {
    return nil
}()

var auxEndCompletion :(()->())? = {
    return nil
}()


var auxAnimations : (()->())?
func transitionAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating {
    let duration = transitionDuration(using: transitionContext)
    let container = transitionContext.containerView

    let toController = transitionContext.viewController(forKey: .to)
    toController?.beginAppearanceTransition(true, animated: true)

    guard
        let to = transitionContext.view(forKey: .to),
        let from = transitionContext.view(forKey: .from)
        else {
            print("To or from view are nil!")
            fatalError()
    }

    container.addSubview(to)

    let animator = UIViewPropertyAnimator(duration: duration, curve: .linear)
    var toStartingPoint: CGPoint
    var fromEndingPoint: CGPoint

    switch self.from {
    case .down:
        toStartingPoint = CGPoint(x: 0, y: -from.bounds.height)
        fromEndingPoint = CGPoint(x: 0, y: from.bounds.height)
    case .top:
        toStartingPoint = CGPoint(x: 0, y: from.bounds.height)
        fromEndingPoint = CGPoint(x: 0, y: -from.bounds.height)
    case .right:
        toStartingPoint = CGPoint(x: from.bounds.width, y: 0)
        fromEndingPoint = CGPoint(x: -from.bounds.width, y: 0)
    case .left:
        toStartingPoint = CGPoint(x: -from.bounds.width, y: 0)
        fromEndingPoint = CGPoint(x: from.bounds.width, y: 0)
    }

    to.transform = CGAffineTransform(translationX: toStartingPoint.x, y: toStartingPoint.y)

    animator.addAnimations({
        from.transform = CGAffineTransform(translationX: fromEndingPoint.x, y: fromEndingPoint.y)
    }, delayFactor: 0.0)

    animator.addAnimations({
        to.transform = .identity
    }, delayFactor: 0.0)


    animator.addCompletion { [weak self] position in
        switch position {
        case .start:
            self?.auxCancelCompletion?()
            transitionContext.completeTransition(false)
            self?.auxAnimationsCancel?()
        case .end:
            self?.auxEndCompletion?()
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
            from.transform = .identity
            to.transform = .identity
        default:
            transitionContext.completeTransition(false)
            self?.auxAnimationsCancel?()
        }
    }

    if let auxAnimations = auxAnimations {
        animator.addAnimations(auxAnimations)
    }

    self.animator = animator
    self.context = transitionContext

    animator.addCompletion { [unowned self] _ in
       //self.animator = nil
       // self.context = nil
    }
    animator.isUserInteractionEnabled = true

    return animator
   }

 }

使用interruptibleAnimator时。它将至少调用此函数两次,你应该提供相同的动画师但不同的动画师。所以你必须这样称呼它:

  func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

 animator =    transitionAnimator(using: transitionContext) as! UIViewPropertyAnimator
 animator.startAnimation()
}
func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating {
    return  animator
}

var animator: UIViewPropertyAnimator!
var context: UIViewControllerContextTransitioning!

或者更简单:

 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
}
func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating {
    if    animator == nil {animator =    transitionAnimator(using: transitionContext) as! UIViewPropertyAnimator
        animator.startAnimation()}
    return  animator
}

这里animator将被调用两次,这是同一个。如果

 func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { 
   return transitionAnimator(using: transitionContext) } 

这不是正确的使用方法,因为动画师会有所不同。

https://developer.apple.com/documentation/uikit/uiviewcontrolleranimatedtransitioning/1829434-interruptibleanimator

请参阅文档中的最后一行。

© www.soinside.com 2019 - 2024. All rights reserved.