iOS Swift: пользовательский интерактивный переход - PullRequest
0 голосов
/ 17 февраля 2019

Я написал пользовательский переход, который отлично работает на модальной презентации.Но в push-презентации позиция просмотра «to» не является анимацией.

Я пробовал тот же код с переключением перевода с альфа-канала, и он работает.

Вид из окна работает отлично, просто просмотр остается неизменным во время анимации.

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
}

Я думал, что это была проблема с делегатами, но навигацияDelgate установлена ​​правильно, иначе я думаю, что я не вижу никакой анимации ..

Настройка делегата:

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
    }
}

и вот пользовательский координатор push, где 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?()
        }

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

Решена анимация снимка целевого представления вместо прямой анимации целевого представления.

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

Просто используйте toViewSnapshot для анимации

0 голосов
/ 18 февраля 2019

То, что я сделал, это так.Надеюсь, это поможет вам.

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

См. Последнюю строку в документе.

...