在Swift中将手势识别器提取到两个函数?

时间:2016-05-21 14:09:54

标签: ios swift delegates uigesturerecognizer subclassing

想象一下iOS屏幕,您可以移动手指向上/向下来做某事(想象一下,"比例"),

或者,

作为一个单独的功能,您可以移动手指左/右来做某事(想象一下,&#34;更改颜色&#34;或&#34;旋转&#34;)。< / p>

他们是

单独的

功能,您只能一次

所以,如果它&#34;开始为&#34;横向版本,它仍然只是一个横向版本。相反,如果它&#34;开始为&#34;垂直版本,它只是一个垂直版本。

这样做有点棘手,我在下面提出了如何做到这一点......基本模式是:

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 的新子类(或其他东西)肯定会更好,因此有两个新概念......

UIHorizontalPanGestureRecognizer

UIVerticalPanGestureRecognizer

那些基本上是一维的pan ..

我绝对不知道你是否会......委托子类?还是上课? (什么课?),或者某种类型的扩展......的确,我基本上对此完全无能为力:))

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

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

如何以这种方式继承/扩展UIPanGestureRecognizer

2 个答案:

答案 0 :(得分:3)

  

但是制作UIPanGestureRecognizer的新子类(或其他东西)肯定会更好,因此有两个新概念......

     
      
  • UIHorizo​​ntalPanGestureRecognizer

  •   
  • UIVerticalPanGestureRecognizer

  •   
     

那些基本上是一维的panners

正确。这正是如何做到的,这是正常的做法。实际上,这正是 的姿势识别器:每个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,以便只能沿着轴直接移动。结果(如果您下载项目本身就可以看到)是一个可以水平或垂直拖动但不以其他方式拖动的视图。

答案 1 :(得分:2)

@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拖到视图控制器的顶部栏上,设置其类,并链接其IBOutlet。在那之后你应该好好去。在视图控制器代码中,您可以设置其回调和平移方向。

更新说明&gt; 我想澄清为什么我让这个类成为NSObject的子类:这个类背后的驱动思想是将任何不必要的代码保留在UIViewController之外。通过继承NSObject,我可以将Object拖到故事板内的视图控制器顶部栏上,并将其类设置为OneDimensionalPan。从那里,我可以将@IBOutlet连接到它。我本可以把它变成一个基类,但是它必须以编程方式实例化。这更清洁了。视图控制器中唯一的代码是访问对象本身(通过@IBOutlet),设置其方向,并设置其回调。