【问题标题】:Swift 3 Gesture Recognizers path.boundingBox is infiniteSwift 3 手势识别器 path.boundingBox 是无限的
【发布时间】:2017-09-02 04:40:07
【问题描述】:

我想了解有关自定义手势识别器的更多信息,因此我正在阅读 Ray Wenderlich 教程,我计划对其进行修改以了解细节以及我可以轻松更改的内容以了解每个部分的工作原理,但它是用以前版本的 Swift。 Swift 更新了大部分代码,我能够手动修复其余代码,只是我无法在屏幕上绘制触摸手势,并且没有任何形状被识别为圆形,我希望两者都可以与同样的问题。网址和代码sn-p如下:

https://www.raywenderlich.com/104744/uigesturerecognizer-tutorial-creating-custom-recognizers

import UIKit
import UIKit.UIGestureRecognizerSubclass

class CircleGestureRecognizer: UIGestureRecognizer {

fileprivate var touchedPoints = [CGPoint]() // point history
var fitResult = CircleResult() // information about how circle-like is the path
var tolerance: CGFloat = 0.2 // circle wiggle room, lower is more circle like higher is oval or other
var isCircle = false
var path = CGMutablePath() // running CGPath - helps with drawing

override func touchesBegan(_ touches: (Set<UITouch>!), with event: UIEvent) {

if touches.count != 1 {
  state = .failed
}
state = .began

let window = view?.window
if let touches = touches, let loc = touches.first?.location(in: window) {
    //print("path 1 \(path.currentPoint)")
  path.move(to: CGPoint(x: loc.x, y: loc.y)) // start the path
    print("path 2 \(path.currentPoint)")
}
//super.touchesBegan(touches, with: event)
}

override func touchesMoved(_ touches: (Set<UITouch>!), with event: UIEvent) {

    // 1
    if state == .failed {
        return
    }

    // 2
    let window = view?.window
    if let touches = touches, let loc = touches.first?.location(in: window) {
        // 3
        touchedPoints.append(loc)

        print("path 3 \(path.currentPoint)")
        path.move(to: CGPoint(x: loc.x, y: loc.y))
        print("path 4 \(path.currentPoint)")

        // 4
        state = .changed
    }
}

override func touchesEnded(_ touches: (Set<UITouch>!), with event: UIEvent) {

    print("path 5 \(path.currentPoint)")
// now that the user has stopped touching, figure out if the path was a circle
fitResult = fitCircle(touchedPoints)

// make sure there are no points in the middle of the circle
    let hasInside = anyPointsInTheMiddle()

    let percentOverlap = calculateBoundingOverlap()

    isCircle = fitResult.error <= tolerance && !hasInside && percentOverlap > (1-tolerance)

state = isCircle ? .ended : .failed
}

override func reset() {
//super.reset()
touchedPoints.removeAll(keepingCapacity: true)
path = CGMutablePath()
isCircle = false
state = .possible
}

fileprivate func anyPointsInTheMiddle() -> Bool {
    // 1
    let fitInnerRadius = fitResult.radius / sqrt(2) * tolerance
    // 2
    let innerBox = CGRect(
        x: fitResult.center.x - fitInnerRadius,
        y: fitResult.center.y - fitInnerRadius,
        width: 2 * fitInnerRadius,
        height: 2 * fitInnerRadius)

    // 3
    var hasInside = false
    for point in touchedPoints {
        if innerBox.contains(point) {
            hasInside = true
            break
        }
    }

    //print(hasInside)
    return hasInside
}

fileprivate func calculateBoundingOverlap() -> CGFloat {
    // 1
    let fitBoundingBox = CGRect(
        x: fitResult.center.x - fitResult.radius,
        y: fitResult.center.y - fitResult.radius,
        width: 2 * fitResult.radius,
        height: 2 * fitResult.radius)
    let pathBoundingBox = path.boundingBox

    // 2
    let overlapRect = fitBoundingBox.intersection(pathBoundingBox)

    // 3
    let overlapRectArea = overlapRect.width * overlapRect.height
    let circleBoxArea = fitBoundingBox.height * fitBoundingBox.width

    let percentOverlap = overlapRectArea / circleBoxArea
    print("Percent Overlap \(percentOverlap)")
    print("pathBoundingBox \(pathBoundingBox)")
    print("path 6 \(path.currentPoint)")

    return percentOverlap
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
state = .cancelled // forward the cancel state
}
}

如教程中所示,这段代码应该将路径的边界框与适合圆形的框进行比较并比较重叠,但是当我打印 pathBoundingBox 时状态为:“pathBoundingBox (inf, inf , 0.0, 0.0)”,这可能是 percentOverlap 为 0 的原因。我认为它是 path.move(to: loc) ,其中 loc 是第一个触摸位置,但 move(to:) 的文档说“这个方法隐含结束当前子路径(如果有)并将当前点设置为点参数中的值。”所以我很难弄清楚为什么 path.boundingBox 是无限的......

【问题讨论】:

  • 如上所述,这是一个大型项目,如网站链接所示。我很犹豫是否一次将所有内容都发布在这里,我不确定它是否会被允许,但这是最好的选择吗?

标签: ios swift uigesturerecognizer cgpath


【解决方案1】:

这不是一个无限边界框,它正好相反——一个零边界框。问题是您的path 是空的。

【讨论】:

  • 这是有道理的,我已经更新了上面的代码以至少显示整个类(如果有帮助,我也可以添加其他类)。第一个路径调用使用 move(to:) 文档指出“此方法隐式结束当前子路径(如果有)并将当前点设置为点参数中的值。”对于(如上所述),所以问题可能不是它从未知点移动到触摸位置,而是没有一个触摸位置链接在一起形成路径,对吗?我会在 touches 移动函数中寻找替换 move(to:) 的东西
  • 就是这样!!!我用 path.addLine(to: loc) 替换了 path.move(to: CGPoint(x: loc.x, y: loc.y)) 现在只有圆圈适合工作,但它也在屏幕上绘制.非常感谢您的帮助,我已经坚持了 2 周,当 swift 从 2.something 更新到 3.something 我没有意识到我允许它在那里选择错误的功能时。谢谢!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多