Swift UIGestureRecogniser 跟随手指移动

36

我正在使用Swift制作一个iOS8应用程序。我希望用户能够使用手势来显示界面的某些部分。例如,用户向上滑动手指,他们滑动的视图移开,跟随手指移动以显示下面的另一个视图。

我想要的是一种手势,可以给出类似于从屏幕顶部拉下的通知框的结果。我一直在查阅文档,但似乎找不到合适的手势。

我看到了一个名为UISwipeGestureRecogniser的手势,但唯一的问题是它不会跟随您的手指移动,而只是在我向上 / 向下滑动手指时运行函数。

这是文档页面: https://developer.apple.com/documentation/uikit/uigesturerecognizer

2个回答

101

你正在寻找 UIPanGestureRecognizer。你可以在这里找到苹果文档 here

这是一个示例处理程序,它将使用手指移动视图。在 Interface Builder 中,向您想要拖动的视图添加一个 UIPanGestureRecognizer。将委托设置为您的 ViewController。将操作设置为此操作:

Swift 2.X:

@IBAction func handlePan(gestureRecognizer: UIPanGestureRecognizer) {
    if gestureRecognizer.state == .Began || gestureRecognizer.state == .Changed {

        let translation = gestureRecognizer.translationInView(self.view)  
        // note: 'view' is optional and need to be unwrapped
        gestureRecognizer.view!.center = CGPointMake(gestureRecognizer.view!.center.x + translation.x, gestureRecognizer.view!.center.y + translation.y)  
        gestureRecognizer.setTranslation(CGPointMake(0,0), inView: self.view)  
    }  
}  

Swift 3:

@IBAction func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
    if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {

        let translation = gestureRecognizer.translation(in: self.view)
        // note: 'view' is optional and need to be unwrapped
        gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
        gestureRecognizer.setTranslation(CGPoint.zero, in: self.view)
    }
}

当然,您可以通过编程方式添加 UIPanGestureRecognizer
在您的 ViewControllerviewDidLoad 中,创建识别器并将其添加到您想要拖动的视图中:
    let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
    self.someDraggableView.addGestureRecognizer(gestureRecognizer)

你能解释一下 gestureRecognizer.setTranslation(CGPointMake(0,0), inView: self.view) 吗?我理解它上面的那行代码,但是我不明白为什么我们需要一个 CGPointZero 来设置识别器的平移。 - Happiehappie
3
@Happiehappie,handlePan处理程序会反复调用,随着用户移动手指而发生变化。默认情况下,平移操作会告诉您自触摸开始以来移动了多远。由于我们正在使用gestureRecognizer来拖动视图并且已经考虑了平移操作,所以我们将其设置为零,这样handlePan下一次被调用时就会报告触摸从上一次handlePan调用到现在移动了多远。 - vacawama
@Fattie 怎么做?有例子吗? - J. Doe
嗨@J.Doe-“动画约束”是iOS编程中最基本的事情之一-您经常这样做。例如,这是我著名的答案之一,解释了如何解决“键盘出现时移动屏幕”的问题:https://dev59.com/yF0a5IYBdhLWcg3wHlil#41808338 - Fattie
我建议你在谷歌上搜索“Swift动画约束”,你会得到很多很多的例子... - Fattie
显示剩余5条评论

0
为了避免滑动超出主视图的边界,可以使用以下代码来帮助您:

class TestPanGestureView: UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }
    
    private func setup() {
        let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
        self.addGestureRecognizer(gestureRecognizer)
    }

    @objc func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
        if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {

            let translation = gestureRecognizer.translation(in: self)
            
            guard let parentController = self.parentContainerViewController(),
                  let navigationController = parentController.navigationController,
                  let gestureRecognizerView = gestureRecognizer.view else { return }
                  
            let fullWidth = parentController.view.frame.width
            let fullHeight = parentController.view.frame.height
            let navbarHeight = navigationController.navigationBar.frame.maxY
            let bottomHeight: CGFloat = 160
            
            var fullTranslationInX = gestureRecognizerView.center.x + translation.x
            // Avoid sliding more than allowed on the right side in X
            if fullTranslationInX > (fullWidth - (self.frame.width / 2))  {
                fullTranslationInX = gestureRecognizer.view!.center.x
            }
            // Avoid sliding more than allowed on the left side in X
            if fullTranslationInX < (self.frame.width / 2) {
                fullTranslationInX = gestureRecognizer.view!.center.x
            }
            

            var fullTranslationInY = gestureRecognizerView.center.y + translation.y
            // Avoid sliding more than allowed on the bottom side in Y
            if fullTranslationInY > ((fullHeight - bottomHeight) - (self.frame.height / 2)) {
                fullTranslationInY = gestureRecognizer.view!.center.y
            }
            // Avoid sliding more than allowed on the top side in Y
            if fullTranslationInY < ( navbarHeight + (self.frame.height / 2)) {
                fullTranslationInY = gestureRecognizer.view!.center.y
            }
            gestureRecognizerView.center = CGPoint(x: fullTranslationInX,
                                                   y: fullTranslationInY)
            gestureRecognizer.setTranslation(CGPoint.zero, in: self)
        }
    }
}

检查这里的结果示例: 示例

也许问题的标题不完整,但问题是关于一种手势,即“跟随他们的手指揭示下面的另一个视角”。你的回答延续了@vacawama的观点,但并没有更接近解决方案。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接