将手势识别器抽象为 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 它的 IBOutlet
s。之后你应该可以开始了。在您的视图控制器代码中,您可以设置其回调和平移方向。
更新说明 >
我想澄清一下为什么我将 class 设为 NSObject
的子 class:class 背后的驱动思想是将任何不必要的代码排除在 [=15= 之外].通过 subclassing NSObject
,我可以将 Object
拖到故事板内视图控制器的顶部栏上,并将其 class 设置为 OneDimensionalPan
。从那里,我可以将 @IBOutlet
s 连接到它。我本可以将其设为基础 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 中实现的实际可下载示例:
观察此处使用的策略。我们制作 UIPanGestureRecognizer 子类。我们重写 touchesBegan
和 touchesMoved
:识别开始的那一刻,一旦下一次触摸出现在错误的轴上,我们就会失败。 (您应该观看 Apple 关于此主题的视频;正如他们所说,当您对手势识别器进行子类化时,您应该“尽早失败,经常失败”。)我们还覆盖了 translationInView
,以便只能直接沿轴移动.结果(如果您下载项目本身,您会看到)是一个可以水平或垂直拖动但不能以其他方式拖动的视图。
想象一个 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 它的 IBOutlet
s。之后你应该可以开始了。在您的视图控制器代码中,您可以设置其回调和平移方向。
更新说明 >
我想澄清一下为什么我将 class 设为 NSObject
的子 class:class 背后的驱动思想是将任何不必要的代码排除在 [=15= 之外].通过 subclassing NSObject
,我可以将 Object
拖到故事板内视图控制器的顶部栏上,并将其 class 设置为 OneDimensionalPan
。从那里,我可以将 @IBOutlet
s 连接到它。我本可以将其设为基础 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 中实现的实际可下载示例:
观察此处使用的策略。我们制作 UIPanGestureRecognizer 子类。我们重写 touchesBegan
和 touchesMoved
:识别开始的那一刻,一旦下一次触摸出现在错误的轴上,我们就会失败。 (您应该观看 Apple 关于此主题的视频;正如他们所说,当您对手势识别器进行子类化时,您应该“尽早失败,经常失败”。)我们还覆盖了 translationInView
,以便只能直接沿轴移动.结果(如果您下载项目本身,您会看到)是一个可以水平或垂直拖动但不能以其他方式拖动的视图。