在scrollview中基于平移手势移动视图控制器

时间:2015-12-05 09:48:35

标签: ios swift

现在我有一个scrollView,它占用了整个视图控制器。下面的代码能够移动scrollView,但我想移动整个视图控制器。我该怎么做?

.container {
  width: 740px;
  margin: 40px auto;
  text-align: justify;
}

我尝试了不同的变体&self; view.center ...." " UIApplication.sharedApplication.rootViewController.view.center .."等

1 个答案:

答案 0 :(得分:3)

我从你的other question推断你想要一个手势来解雇这个视图控制器。我建议您使用UIPercentDrivenInteractiveTransition交互控制器使用自定义转换,并让手势只是操纵交互控制器,而不是在手势中自己操纵视图。这实现了相同的用户体验,但其方式与Apple的自定义转换范例一致。

这里有趣的问题是你想如何在自定义消除转换手势和滚动视图手势之间进行描述。你想要的是一些以某种方式受限制的姿态。这里有很多选择:

  • 如果滚动视图仅为左右,则自定义平移手势子类如果水平使用则会失败;

  • 如果滚动视图也是上下的,那么就有一个顶部的“屏幕边缘手势识别器”或添加一些视觉元素,这是一个“抓杆”,你可以将平移手势绑定

但是,无论你设计这个手势,滚动视图的手势都要求你自己的手势在触发之前失败。

例如,如果您想要一个屏幕边缘手势识别器,它将如下所示:

class SecondViewController: UIViewController, UIViewControllerTransitioningDelegate {

    @IBOutlet weak var scrollView: UIScrollView!

    var interactionController: UIPercentDrivenInteractiveTransition?

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        modalPresentationStyle = .Custom
        transitioningDelegate = self
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // ...

        let edge = UIScreenEdgePanGestureRecognizer(target: self, action: "handleScreenEdgeGesture:")
        edge.edges = UIRectEdge.Top
        view.addGestureRecognizer(edge)
        for gesture in scrollView.gestureRecognizers! {
            gesture.requireGestureRecognizerToFail(edge)
        }
    }

    // because we're using top edge gesture, hide status bar

    override func prefersStatusBarHidden() -> Bool {
        return true
    }

    func handleScreenEdgeGesture(gesture: UIScreenEdgePanGestureRecognizer) {
        switch gesture.state {
        case .Began:
            interactionController = UIPercentDrivenInteractiveTransition()
            dismissViewControllerAnimated(true, completion: nil)
        case .Changed:
            let percent = gesture.translationInView(gesture.view).y / gesture.view!.frame.size.height
            interactionController?.updateInteractiveTransition(percent)
        case .Cancelled:
            fallthrough
        case .Ended:
            if gesture.velocityInView(gesture.view).y < 0 || gesture.state == .Cancelled || (gesture.velocityInView(gesture.view).y == 0 && gesture.translationInView(gesture.view).y < view.frame.size.height / 2.0) {
                interactionController?.cancelInteractiveTransition()
            } else {
                interactionController?.finishInteractiveTransition()
            }
            interactionController = nil
        default: ()
        }
    }

    @IBAction func didTapDismissButton(sender: UIButton) {
        dismissViewControllerAnimated(true, completion: nil)
    }

    // MARK: UIViewControllerTransitioningDelegate

    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return DismissAnimation()
    }

    func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return interactionController
    }

}

class DismissAnimation: NSObject, UIViewControllerAnimatedTransitioning {

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return 0.25
    }

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        let from = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
        let container = transitionContext.containerView()!

        let height = container.bounds.size.height

        UIView.animateWithDuration(transitionDuration(transitionContext), animations:
            {
                from.view.transform = CGAffineTransformMakeTranslation(0, height)
            }, completion: { finished in
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
            }
        )
    }

}

就个人而言,我发现顶部和底部屏幕边缘手势的概念是一个糟糕的用户体验,所以我个人改变这个模态演示文稿从右边滑入,然后从左边缘向右边滑动感觉合乎逻辑,并且不会干扰内置的顶部下拉(适用于iOS通知)。或者,如果滚动视图仅水平滚动,那么如果它不是垂直平移,您可以使用自己的垂直平移手势。

或者,如果滚动视图仅向左和向右滚动,则可以添加自己的平移手势,只有当您通过(a)使用UIGestureRecognizerDelegate来识别向下平移时才能识别; (b)再次设置滚动视图手势,以便在我们的下拉手势失败时识别手势:

override func viewDidLoad() {
    super.viewDidLoad()

    // ...

    let pan = UIPanGestureRecognizer(target: self, action: "handlePan:")
    pan.delegate = self
    view.addGestureRecognizer(pan)

    for gesture in scrollView.gestureRecognizers! {
        gesture.requireGestureRecognizerToFail(pan)
    }
}

func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
    if let gesture = gestureRecognizer as? UIPanGestureRecognizer {
        let translation = gesture.translationInView(gesture.view)
        let angle = atan2(translation.x, translation.y)
        return abs(angle) < CGFloat(M_PI_4 / 2.0)
    }
    return true
}

func handlePan(gesture: UIPanGestureRecognizer) {
    // the same as the `handleScreenEdgeGesture` above
}

就像我说的,这里有很多选择。但是你没有分享足够的设计给我们进一步的建议。

但是上面说明的基本思想是,你不应该自己移动视图,而是使用自己的动画师和自己的交互式控制器进行自定义过渡。

有关详细信息,请参阅WWDC 2013 Custom Transitions Using View Controllers(以及WWDC 2014 A Look Inside Presentation Controllers,如果您想了解有关自定义转换演变的更多信息,请参阅。