[英]Moving view controller based on pan gesture in scrollview
现在,我有一个scrollView占据了整个视图控制器。 下面的代码能够移动scrollView,但是我想移动整个视图控制器。 我该怎么办?
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 ..”等不同的变体。
我从您的另一个问题推断出,您想要手势以关闭该视图控制器。 建议您UIPercentDrivenInteractiveTransition
通过UIPercentDrivenInteractiveTransition
交互控制器使用自定义过渡, UIPercentDrivenInteractiveTransition
让手势仅操作交互控制器。 这样可以实现相同的UX,但其方式与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 自定义过渡 (如果需要有关自定义过渡的更多信息,请参阅WWDC 2014 A Look Inside Presentation Controllers )。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.