2017-09-02 20 views
-1

カスタムジェスチャー認識ツールについて詳しく知りたいので、私は詳細を学ぶために変更する予定のRay Wenderlichチュートリアルを読んでいました。各作品は動作しますが、以前のバージョンの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になっている可能性があります。最初のタッチ位置ですが、move(to :)のドキュメントには、「このメソッドは暗黙的に現在のサブパスを終了し、現在のポイントをポイントパラメータの値に設定します」と表示します。だから私はpath.boundingBoxが無限である理由を理解するのに苦労しています...

+0

私が上に述べたように、それはウェブサイトへのリンクに示されているような大きなプロジェクトです。私はすぐにここにすべてを投稿することを躊躇していましたが、それが許されるかどうかは確信が持てませんでしたが、それは最高の選択肢ですか? – Dominick

答えて

1

これは無限のバウンディングボックスではなく、それはちょうど反対です - ゼロのバウンディングボックスです。問題はあなたのpathが空であることです。

+0

これは理にかなっていますが、私は上記のコードを更新して、クラス全体を少なくとも表示しました(そして、もし役に立つと他のクラスも追加できます)。非常に最初のパス呼び出しでは、ドキュメントが "現在のサブパスを暗黙的に終了し(存在する場合)、現在のポイントをポイントパラメータの値に設定する"というmove(to :)を使用します。 (上記のように)、問題は未知の点からタッチ位置に移動しているのではないかもしれませんが、タッチ位置のどれも一緒にリンクして正しいパスを形成していませんか?私は移動された(to :)に触れる移動された機能で何かを探すだろう – Dominick

+0

それはそれだった!私は をpath.moveに置き換えました(CGPoint(x:loc.x、y:loc.y)) と path.addLine(to:loc) 今はサークルフィットの作業のみですが、画面も同様です。お手伝いいただき、ありがとうございました。私はこれを2週間続けました.2時から3時にすばやく更新されました。間違った機能を選択することを認めていませんでした。ありがとう!!! – Dominick

関連する問題