【问题标题】:iOS Interactive Animation SwiftiOS 交互式动画 Swift
【发布时间】:2016-10-06 14:58:45
【问题描述】:

我一生都无法理解为什么这不起作用。

有两个 VC:A 和 B。

我想在 VC A 上向右滑动以显示 VC B,但希望使其具有交互性,以便用户可以在两个 VC 之间拖动(例如在 Instagram 主屏幕上,当您左右滑动以转到相机和消息时) .目前,它没有“拖动”。您可以在 VC A 上滑动,它会转到 VC B。

这是我向右滑动的动画对象:

class SlideRightTransitionAnimator: NSObject {

let duration = 0.5
var isPresenting = false
let customInteractiveTransition = CustomInteractiveTransition()

}

// MARK: UIViewControllerTransitioningDelegate
extension SlideRightTransitionAnimator: UIViewControllerTransitioningDelegate {

// Return the animator when presenting a VC
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    isPresenting = true
    return self
}

// Return the animator used when dismissing from a VC
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    isPresenting = false
    return self
}

// Add the interactive transition for Presentation only
func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
    return customInteractiveTransition.transitionInProgress ? customInteractiveTransition : nil
}
}

// MARK: UIViewControllerTransitioningDelegate
extension SlideRightTransitionAnimator: UIViewControllerAnimatedTransitioning {

// Return how many seconds the transiton animation will take
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return duration
}

// Animate a change from one VC to another
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

    // Get reference to our fromView, toView and the container view that we should perform the transition
    let container = transitionContext.containerView
    let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
    let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!

    // Set up the transform we'll use in the animation
    let offScreenRight = CGAffineTransform(translationX: container.frame.width, y: 0)
    let offScreenLeft = CGAffineTransform(translationX: -container.frame.width, y: 0)

    // Start the toView to the right of the screen
    if isPresenting {
        toView.transform = offScreenLeft
    }

    // Add the both views to our VC
    container.addSubview(toView)
    container.addSubview(fromView)

    // Perform the animation
    UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: [], animations: {

        if self.isPresenting {
            fromView.transform = offScreenRight
            toView.transform = CGAffineTransform.identity
        }
        else {
            fromView.transform = offScreenLeft
            toView.transform = CGAffineTransform.identity
        }

        }, completion: { finished in
            // Tell our transitionContext object that we've finished animating
            transitionContext.completeTransition(true)
    })
}

}

这是我的交互式过渡控制器

class CustomInteractiveTransition: UIPercentDrivenInteractiveTransition {

weak var viewController : UIViewController!
var shouldCompleteTransition = false
var transitionInProgress = false
var completionSeed: CGFloat {
    return 1 - percentComplete
}

func attachToViewController(viewController: UIViewController) {
    self.viewController = viewController
    setupPanGestureRecognizer(view: viewController.view)
}

private func setupPanGestureRecognizer(view: UIView) {
    view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture)))
}

func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) {
    let viewTranslation = gestureRecognizer.translation(in: gestureRecognizer.view!.superview!)
    var progress = (viewTranslation.x / 200)
    progress = CGFloat(fminf(fmaxf(Float(progress), 0.0), 1.0))

    switch gestureRecognizer.state {
    case .began:
        transitionInProgress = true
        viewController.dismiss(animated: true, completion: nil)
    case .changed:
        shouldCompleteTransition = progress > 0.5
        update(progress)
    case .cancelled, .ended:
        transitionInProgress = false
        if !shouldCompleteTransition || gestureRecognizer.state == .cancelled {
            cancel()
        } else {
            finish()
        }
    default:
        print("Swift switch must be exhaustive, thus the default")
    }
}

}

最后是 VC A 的代码:

class ViewControllerA: UITableViewController {

let slideRightTransition = SlideRightTransitionAnimator()
let customInteractiveTransition = CustomInteractiveTransition()

 override func viewDidLoad() {
    super.viewDidLoad()

    // Add a Pan Gesture to swipe to other VC
    let swipeGestureRight = UISwipeGestureRecognizer(target: self, action: #selector(swipeGestureRightAction))
    swipeGestureRight.direction = .right
    view.addGestureRecognizer(swipeGestureRight)
 }

  // MARK: Pan gestures
func swipeGestureRightAction() {
    performSegue(withIdentifier: "showMapSegue", sender: self)
}

 // MARK: Prepare for segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if segue.identifier == "showVCB" {

        // This gets a reference to the screen that we're about to transition to and from
        let toViewController = segue.destination as UIViewController

        // Instead of using the default transition animation, we'll ask the segue to use our custom SlideRightTransitionAnimator object to manage the transition animation
        toViewController.transitioningDelegate = slideRightTransition

        // Add the Interactive gesture transition to the VC
        customInteractiveTransition.attachToViewController(viewController: toViewController)
    }
}

提前谢谢你!!!

【问题讨论】:

    标签: ios swift animation transition interactive


    【解决方案1】:

    在 VC A 的 viewDidLoad 中,您需要将 UISwipeGestureRecognizer 替换为 UIPanGestureRecognizer。然后在手势处理函数中实现适当的 .changed 状态。

    编辑:此外,为了实现控制器之间的滑动转换,我强烈建议改用 UIPageViewController。那甚至可能是自定义 UICollectionView 解决方案。

    【讨论】:

    • 抱歉回复晚了,但是你是对的——关键是使用 UIPageViewController。谢谢
    【解决方案2】:

    在函数 handlePanGesture 中,您从 VC A 获取翻译参考(即 gestureRecognizer.view!.superview!) 但取而代之的是从 UIWindow 中引用。 (即 UIApplication.shared.windows.last

    gestureRecognizer.view!.superview! 替换为 UIApplication.shared.windows.last

    it's worked for me.
    

    【讨论】: