2017-09-02 64 views
-1

我想了解更多關於自定義手勢識別器的知識,所以我正在閱讀Ray Wenderlich教程,我計劃修改它以便了解詳細信息以及我可以輕鬆更改的內容以瞭解如何每個作品都有效,但它是用Swift的先前版本編寫的。 Swift更新了大部分代碼,並且我能夠手動修復其餘部分,但我無法在屏幕上繪製觸摸手勢,並且沒有形狀被識別爲圓形,我希望它們都能與之綁定同樣的問題。該網站的代碼片段如下:Swift 3手勢識別器path.boundingBox是無限的

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是第一個觸摸位置,但移動文檔(to :)表示「此方法隱式結束當前子路徑(如果有)並將當前點設置爲point參數中的值。」所以我正在努力弄清楚爲什麼path.boundingBox是無限的...

+0

正如我上面所述,這是一個大型項目,如鏈接到網站所示。我猶豫是否立即將它全部發布在這裏,我不確定它甚至會被允許,但是這是最好的選擇嗎? – Dominick

回答

1

這不是一個無限的邊界框,它只是相反的 - 一個零邊界框。問題是您的path是空的。

+0

這很有道理,我已經更新了上面的代碼,至少顯示了整個類(如果有幫助,我也可以添加其他類)。第一個路徑調用使用move(to :)文檔指出「此方法隱式結束當前子路徑(如果有)並將當前點設置爲point參數中的值。」因爲(正如我上面提到的那樣),所以問題可能不是它從未知點移動到觸摸位置,而是沒有任何觸摸位置連接在一起形成正確的路徑?我會尋找一些東西來取代移動(與:)在觸摸移動功能 – Dominick

+0

這就是它!我替換了 path.move(到:CGPoint(x:loc.x,y:loc.y)) 與 path.addLine(to:loc) 現在只有這個圓適合工作,但它會吸引屏幕也是如此。非常感謝你的幫助,我一直堅持這個爲期2周,當時迅速更新爲2.從某事到事情3.我沒有意識到我允許它在那裏選擇錯誤的功能。謝謝!!! – Dominick