我用swiftui實作了一個可以識別用戶手勢和畫線的demo。現在我希望它在行尾添加一個箭頭,并且不同的段有不同角度的箭頭。我應該怎么辦?
這是我的代碼
struct LineView: View {
@State var removeAll = false
@State var lines = [CGPoint]()
var body: some View {
ZStack {
Rectangle()
.cornerRadius(20)
.opacity(0.1)
.shadow(color: .gray, radius: 4, x: 0, y: 2)
Path { path in
path.addLines(lines)
}
.stroke(lineWidth: 3)
}
.gesture(
DragGesture()
.onChanged { state in
if removeAll {
lines.removeAll()
removeAll = false
}
lines.append(state.location)
}
.onEnded { _ in
removeAll = true
}
)
.frame(width: 370, height: 500)
}
}
uj5u.com熱心網友回復:
有很多方法可以確定如何定位和旋轉行尾的箭頭。大多數情況下,您需要最后兩個點來確定箭頭的位置和旋轉。
如果您已經繪制了箭頭(路徑或影像),那么使用變換可能是最簡單的。它應該如下所示:
private func arrowTransform(lastPoint: CGPoint, previousPoint: CGPoint) -> CGAffineTransform {
let translation = CGAffineTransform(translationX: lastPoint.x, y: lastPoint.y)
let angle = atan2(lastPoint.y-previousPoint.y, lastPoint.x-previousPoint.x)
let rotation = CGAffineTransform(rotationAngle: angle)
return rotation.concatenating(translation)
}
這里的關鍵是使用atan2哪個是真正的救生員。它基本上是反正切,不需要額外的 if 陳述句來確定兩點之間的角度。它接受 delta-y 和 delta-x;這就是所有需要知道的。使用這些資料,您可以創建一個平移矩陣和一個旋轉矩陣,然后可以將它們連接起來以獲得最終結果。
要應用它,您只需像下面這樣使用它:
arrowPath()
.transform(arrowTransform(lastPoint: lines[lines.count-1], previousPoint: lines[lines.count-2]))
.fill()
我只是在這里用一條路徑畫了一個箭頭(0, 0),然后填充它。
我使用的全部內容是:
struct LineView: View {
@State var removeAll = false
@State var lines = [CGPoint]()
private func arrowPath() -> Path {
// Doing it rightwards
Path { path in
path.move(to: .zero)
path.addLine(to: .init(x: -10.0, y: 5.0))
path.addLine(to: .init(x: -10.0, y: -5.0))
path.closeSubpath()
}
}
private func arrowTransform(lastPoint: CGPoint, previousPoint: CGPoint) -> CGAffineTransform {
let translation = CGAffineTransform(translationX: lastPoint.x, y: lastPoint.y)
let angle = atan2(lastPoint.y-previousPoint.y, lastPoint.x-previousPoint.x)
let rotation = CGAffineTransform(rotationAngle: angle)
return rotation.concatenating(translation)
}
var body: some View {
ZStack {
Rectangle()
.cornerRadius(20)
.opacity(0.1)
.shadow(color: .gray, radius: 4, x: 0, y: 2)
Path { path in
path.addLines(lines)
}
.stroke(lineWidth: 3)
if lines.count >= 2 {
arrowPath()
.transform(arrowTransform(lastPoint: lines[lines.count-1], previousPoint: lines[lines.count-2]))
.fill()
}
}
.gesture(
DragGesture()
.onChanged { state in
if removeAll {
lines.removeAll()
removeAll = false
}
lines.append(state.location)
}
.onEnded { _ in
removeAll = true
}
)
.frame(width: 370, height: 500)
}
}
它仍然需要一些作業。洗掉線上的最后一個點或移動箭頭以與最后一行重疊。但我認為你應該能夠從這里拿走它。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/483970.html
