カスタムジェスチャー認識ツールについて詳しく知りたいので、私は詳細を学ぶために変更する予定の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が無限である理由を理解するのに苦労しています...
私が上に述べたように、それはウェブサイトへのリンクに示されているような大きなプロジェクトです。私はすぐにここにすべてを投稿することを躊躇していましたが、それが許されるかどうかは確信が持てませんでしたが、それは最高の選択肢ですか? – Dominick