在scrollview中基于平移手势移动视图控制器 [英] Moving view controller based on pan gesture in scrollview

查看:109
本文介绍了在scrollview中基于平移手势移动视图控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Right now I have a scrollView that takes up the entire view controller. The code below is able to move the scrollView around but I want to move the whole view controller around. How would I do that?

override func viewDidLoad() {
        pan = UIPanGestureRecognizer(target: self, action: "handlePan:")
        self.scrollview.addGestureRecognizer(pan)
}

func handlePan(recognizer:UIPanGestureRecognizer!) {

    switch recognizer.state {
    case .Changed:
        handlePanChanged(recognizer); break
    case .Ended:
        handlePanTerminated(recognizer); break
    case .Cancelled:
        handlePanTerminated(recognizer); break
    case .Failed:
        handlePanTerminated(recognizer); break
    default: break
    }
}

func handlePanChanged(recognizer:UIPanGestureRecognizer!) {
    if let view = recognizer.view {
        var translation = recognizer.translationInView(self.view)
        println("moving")
        view.center = CGPointMake(view.center.x, view.center.y + translation.y);
        recognizer.setTranslation(CGPointZero, inView: self.view)
    }
}

我尝试了不同的self.view.center ....UIApplication.sharedApplication.rootViewController.view.center ..等等。

I've tried different variations of "self.view.center ...." "UIApplication.sharedApplication.rootViewController.view.center.." etc.

推荐答案

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

I infer from your other question that you want to a gesture to dismiss this view controller. Rather than manipulating the view yourself in the gesture, I'd suggest you use custom transition with a UIPercentDrivenInteractiveTransition interaction controller, and have the gesture just manipulate the interaction controller. This achieves the same UX, but in a manner consistent with Apple's custom transitions paradigm.

这里有趣的问题是如何在自定义关闭转换手势和滚动视图的手势。你想要的是一些以某种方式受到约束的姿态。这里有很多选项:

The interesting question here is how do you want to delineate between the custom dismiss transition gesture and the scroll view gesture. What you want is some gesture that is constrained in some fashion. There are tons of options here:


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

  • If the scroll view is left-right only, have a custom pan gesture subclass that fails if you use it horizontally;

如果滚动视图也是上下,那么有一个顶部的屏幕边缘手势识别器或添加一些视觉元素这是一个抓杆,你可以用它来平衡手势

If the scroll view is up-down, too, then have a top "screen edge gesture recognizer" or add some visual element that is a "grab bar" to which you tie a pan gesture

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

But however you design this gesture to work, have the scroll view's gestures require that your own gesture fails before they trigger.

例如,如果你想要一个屏幕边缘手势识别器,那将是:

For example, if you wanted a screen edge gesture recognizer, that would look like:

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)通知)。或者,如果滚动视图仅水平滚动,那么如果它不是垂直平移,您可以使用自己的垂直平移手势。

Personally, I find the notion of having top and bottom screen edge gestures to be a bad UX, so I'd personally change this modal presentation to slide in from the right, and then swiping from left edge to the right feels logical, and doesn't interfere with the built in top pull down (for iOS notifications). Or if the scroll view only scrolls horizontally, then you can just have your own vertical pan gesture that fails if it's not a vertical pan.

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

Or, if the scroll view only scrolls left and right, you can add your own pan gesture that is only recognized when you pull down by (a) using UIGestureRecognizerDelegate to recognize downward pans only; and (b) again setting the scroll view gestures to only recognize gestures if our pull-down gesture fails:

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
}

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

Like I said, tons of options here. But you haven't shared enough of your design for us to advise you further on that.

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

But the above illustrates the basic idea, that you shouldn't be moving the view around yourself, but rather use custom transition with your own animators and your own interactive controller.

有关详细信息,请参阅WWDC 2013 使用View Controllers进行自定义转换(以及WWDC 2014 A Look内部演示控制器,如果您想了解有关自定义转换演变的更多信息,请执行此操作。

For more information, see WWDC 2013 Custom Transitions Using View Controllers (and also WWDC 2014 A Look Inside Presentation Controllers, if you want a little more information on the evolution of custom transitions).

这篇关于在scrollview中基于平移手势移动视图控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆