Como fazer com que algum ponto se torne arrastável através de um conjunto de arestas de visualização como no vídeo:
Em vez de arrasto livre:
Nem sei por onde começar, pois não consigo medir os limites de uma visualização sem o GeometryReader.
Entretanto, o GeometryReader não é adequado neste caso porque são visualizações diferentes em camadas separadas.
Exemplo de visualização:
struct ContentView: View {
@State var point: CGPoint = .zero
var body: some View {
ZStack {
//foreach Nodes
NodeView()
NodeView()
.offset(x:0, y:100)
//foreach Points
BezierPoint(p1: $point)
}
}
}
struct NodeView : View {
// var nodeViewModel: NodeViewModel
// with exact location in space
var body: some View {
Text("Business")
.multilineTextAlignment(.center)
.foregroundStyle(.red)
.shadow(color: .black, radius: 2 )
.frame(minHeight: 40)
.padding( EdgeInsets(horizontal: 20, vertical: 14) )
.background {
// ANY Shape can be here
RoundedRectangle(cornerRadius: 10)
}
}
}
struct BezierPoint: View {
@Binding var p1: CGPoint
let pointsSize: CGFloat = 15
var body: some View {
GeometryReader { reader in
ControlPointHandle(size: pointsSize)
.offset( CGSize(width: p1.x + reader.size.width/2, height: p1.y + reader.size.height/2) )
.gesture(
DragGesture()
.onChanged { value in
self.p1 = value.location.relativeToCenter(of: reader.size, minus: true)
}
)
}
}
}
private struct ControlPointHandle: View {
let size: CGFloat
var body: some View {
Circle()
.frame(width: size, height: size)
.overlay(
Circle()
.stroke(Color.blue, lineWidth: 2)
)
.offset(x: -size/2, y: -size/2)
}
}
fileprivate extension CGPoint {
func relativeToCenter(of size: CGSize, minus: Bool = false) -> CGPoint {
let a: CGFloat = minus ? -1 : 1
return CGPoint(x: x + a * size.width/2, y: y + a * size.height/2)
}
}
A técnica mostrada na resposta para É possível detectar qual View atualmente cai sob o local de um DragGesture? pode ser usada para detectar quando uma forma está sob o ponto de arrasto (foi minha resposta). Isso usa um
GeometryReader
no fundo da forma, o que deve funcionar mesmo se você tiver uma view multicamadas.Para encontrar o ponto ao longo da borda da forma que está mais próximo do ponto de arrasto, eu sugeriria a seguinte abordagem:
Path
funçãolineIntersection(_:eoFill:)
para encontrar a intersecção da linha com a forma.Anteriormente, você estava envolvendo cada ponto com um
GeometryReader
. AGeometryReader
é ganancioso e consome todo o espaço disponível, então isso estava aumentando o tamanho de cada ponto para o tamanho total da visualização pai. Em vez de fazer dessa forma, eu sugeriria usar.onGeometryChange
para medir a posição de cada ponto.Aqui está o exemplo atualizado para mostrar que ele funciona. Ele inclui um segundo ponto, para que a independência dos pontos também possa ser testada.