将手势识别器抽象为 Swift 中的两个函数?

Abstracting gesture recognizer to two functions in Swift?

想象一个 iOS 屏幕,您可以在其中移动手指 up/down 来做某事(想象说,“缩放”),

或者,

作为一项单独的功能,您可以移动手指 left/right 来做某事(想象一下,“改变颜色”或“旋转”)。

他们是

分开

功能,你一次只能做一个

所以,如果它“开始”是一个水平版本,它仍然只是一个水平版本。相反,如果它“开始”是一个垂直版本,它仍然只是一个垂直版本。

这样做有点棘手,我在下面详细介绍了如何做...基本模式是:

if (r.state == .Began || panway == .WasZeros )
    {
    prev = tr
    if (tr.x==0 && tr.y==0)
        {
        panway = .WasZeros
        return
        }
    if (abs(tr.x)>abs(tr.y)) ... set panway
    }

这非常有效,下面是 Swift 中的具体操作方法。

在故事板中取一个 UIPanGestureRecognizer,将其拖到相关视图中。将委托连接到视图控制器并将出口设置为此调用 ultraPan:

enum Panway
    { 
    case Vertical
    case Horizontal
    case WasZeros
    }
var panway:Panway = .Vertical
var prev:CGPoint!

@IBAction func ultraPan(r:UIPanGestureRecognizer!)
    {
    let tr = r.translationInView(r.view)
    
    if (r.state == .Began || panway == .WasZeros )
        {
        prev = tr
        
        if (tr.x==0 && tr.y==0)
            {
            panway = .WasZeros
            return
            }
        
        if (abs(tr.x)>abs(tr.y))
            {
            panway = .Horizontal
            }
        else
            {
            panway = .Vertical
            }
        }
    
    if (panway == .Horizontal)  // your left-right function
        {
        var h = tr.x - prev.x
        let sensitivity:CGFloat = 50.0
        h = h / sensitivity
        // adjust your left-right function, example
        someProperty = someProperty + h
        }
    
    if (panway == .Vertical)    // bigger/smaller
        {
        var v = tr.y - prev.y
        let sensitivity:CGFloat = 2200.0
        v = v / sensitivity
        // adjust your up-down function, example
        someOtherProperty = someOtherProperty + v
        }
    
    prev = tr
    }

没关系。

但是做一个UIPanGestureRecognizer的新子class(或其他东西)肯定会更好,这样就有两个新概念..... .

UIHorizontalPanGestureRecognizer

UIVerticalPanGestureRecognizer

那些基本上是一维平移器。

我完全不知道你是否会...... subclass 代表们?还是 class? (什么class?),或者某种扩展......事实上,我基本上对此一无所知:)

目标在一个人的代码中,你可以有这样的东西......

@IBAction func horizontalPanDelta( ..? )
    {
    someProperty = someProperty + delta
    }
@IBAction func verticalPanDelta( ..? )
    {
    otherProperty = otherProperty + delta
    }

这样怎么inherit/extendUIPanGestureRecognizer??

@Joe,这是我为了这个问题快速拼凑起来的东西。为了制作方便,我只是给它一个回调,而不是实现一个目标-动作系统。随意更改它。

enum PanDirection {
    case Horizontal
    case Vertical
}

class OneDimensionalPan: NSObject {

    var handler: (CGFloat -> ())?
    var direction: PanDirection

    @IBOutlet weak var panRecognizer: UIPanGestureRecognizer! {
        didSet {
            panRecognizer.addTarget(self, action: #selector(panned))
        }
    }

    @IBOutlet weak var panView: UIView!

    override init() {
        direction = .Horizontal
        super.init()
    }

    @objc private func panned(recognizer: UIPanGestureRecognizer) {
        let translation = panRecognizer.translationInView(panView)
        let delta: CGFloat
        switch direction {
        case .Horizontal:
            delta = translation.x
            break
        case .Vertical:
            delta = translation.y
            break
        }
        handler?(delta)
    }
}

在情节提要中,将 UIPanGestureRecognizer 拖到视图控制器上,然后将 Object 拖到视图控制器的顶部栏上,设置其 class,然后 link 它的 IBOutlets。之后你应该可以开始了。在您的视图控制器代码中,您可以设置其回调和平移方向。

更新说明 > 我想澄清一下为什么我将 class 设为 NSObject 的子 class:class 背后的驱动思想是将任何不必要的代码排除在 [=15= 之外].通过 subclassing NSObject,我可以将 Object 拖到故事板内视图控制器的顶部栏上,并将其 class 设置为 OneDimensionalPan。从那里,我可以将 @IBOutlets 连接到它。我本可以将其设为基础 class,但随后必须以编程方式对其进行实例化。这要干净得多。视图控制器中唯一的代码是访问对象本身(通过 @IBOutlet)、设置它的方向和设置它的回调。

But it would surely be better to make a new subclass (or something) of UIPanGestureRecognizer, so that there are two new concepts......

  • UIHorizontalPanGestureRecognizer

  • UIVerticalPanGestureRecognizer

Those would be basically one-dimensional panners

正确。这正是如何去做的,也是正常的做法。事实上,这正是手势识别器 for:每个 g.r。仅识别其 自己的 手势,当它识别时,它会导致竞争手势识别器后退。这就是手势识别器的全部!否则,我们仍会回到 g.r 之前。纯净的日子 touchesBegan 等等(哦,恐怖)。

我的在线书籍实际上讨论了您在这里给出的例子

http://www.apeth.com/iOSBook/ch18.html#_subclassing_gesture_recognizers

这是在 Swift 中实现的实际可下载示例:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch05p203gestureRecognizers/ch18p541gestureRecognizers/HorizVertPanGestureRecognizers.swift

观察此处使用的策略。我们制作 UIPanGestureRecognizer 子类。我们重写 touchesBegantouchesMoved:识别开始的那一刻,一旦下一次触摸出现在错误的轴上,我们就会失败。 (您应该观看 Apple 关于此主题的视频;正如他们所说,当您对手势识别器进行子类化时,您应该“尽早失败,经常失败”。)我们还覆盖了 translationInView,以便只能直接沿轴移动.结果(如果您下载项目本身,您会看到)是一个可以水平或垂直拖动但不能以其他方式拖动的视图。