SwiftUI:在列表中的两个视图之间画一条线/如何确定视图的中心位置?

SwiftUI: Drawing a line between two views in a list / how to determine the center location of a view?

我想在按下“连接”按钮时在选定的源视图和选定的目标视图之间画一条线。 据我了解,我需要这些视图的(中心?)CGPoint ... 如何确定 forEach-HStack-list 中视图的中心 CGPoint?

两个列表中的元素将是 removed/added。

struct ContentView: View {
    @State private var selectedTarget: Int = 0
    @State private var selectedSource: Int = 3
    @State private var isConnected = false
    
    
    var body: some View {
       
        ZStack {
            VStack {
                HStack {
                    ForEach(0..<6) { index in
                        Text("Target \(index)")
                            .padding()
                            .foregroundColor(.white)
                            .background(selectedTarget == index ? .red : .black)
                            .onTapGesture {
                                selectedTarget = index
                            }
                    }
                }
                
                List {
                    EmptyView()
                }
                .frame(width: 400, height: 400, alignment: .center)
                .border(.black, width: 2)
        
                HStack {
                    ForEach(0..<6) { index in
                        Text("Source \(index)")
                            .padding()
                            .foregroundColor(.white)
                            .background(selectedSource == index ? .orange : .black)
                            .onTapGesture {
                                selectedSource = index
                            }
                    }
                }
                Button(isConnected ? "CUT" : "CONNECT") {
                    isConnected.toggle()
                }
                .padding()
            }
        }
        
    }
    
}

这是粗略的演示代码,并从这段代码中汲取灵感。 您可以通过首先通过 GeometryReader 找到 Text 的位置并绘制这些点之间的路径来实现此目的。

struct ContentView: View {
    @State private var selectedTarget: Int = 0
    @State private var selectedSource: Int = 3
    @State private var isConnected = false
    
    @State private var targetCGPoint: CGPoint = .zero
    @State private var sourceCGPoint: CGPoint = .zero
    
    var body: some View {
        
        ZStack {
            if isConnected {
                getPath()
            }
            VStack {
                HStack {
                    ForEach(0..<6) { index in
                        GeometryReader { geo in
                        Text("Target \(index)")
                            .padding()
                            .foregroundColor(.white)
                            .background(selectedTarget == index ? Color.red : Color.black)
                            .onTapGesture {
                                let size = geo.size
                                targetCGPoint = CGPoint(x: geo.frame(in: .global).origin.x + (size.width / 2), y: geo.frame(in: .global).origin.y)
                                print("Target Global center: \(geo.frame(in: .global).midX) x \(geo.frame(in: .global).midY)")
                                selectedTarget = index
                            }
                        }
                    }
                }
                
                // Removed list for demo
                Spacer()
                
                HStack {
                    ForEach(0..<6) { index in
                        GeometryReader { geo in
                            Text("Source \(index)")
                                .padding()
                                .foregroundColor(.white)
                                .background(selectedSource == index ? Color.orange : Color.black)
                                .onTapGesture {
                                    let size = geo.size
                                    sourceCGPoint = CGPoint(x: geo.frame(in: .global).origin.x + (size.width / 2), y: geo.frame(in: .global).origin.y)
                                    print("Source Global center: \(geo.frame(in: .global).midX) x \(geo.frame(in: .global).midY)")
                                    selectedSource = index
                                }
                        }
                        
                    }
                }
                Button(isConnected ? "CUT" : "CONNECT") {
                    isConnected.toggle()
                }
                .padding()
            }
        }
        
    }
    
    func getPath() -> some View {
        Path { path in
            path.move(to: sourceCGPoint)
            path.addLine(to: targetCGPoint)
        }
        .stroke(Color.blue, lineWidth: 10)
    }
}