Skip to content

Instantly share code, notes, and snippets.

@bjhomer
Last active November 5, 2022 05:31
Show Gist options
  • Star 44 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save bjhomer/c1da7d1d689172dd21bc4795861df99d to your computer and use it in GitHub Desktop.
Save bjhomer/c1da7d1d689172dd21bc4795861df99d to your computer and use it in GitHub Desktop.
Creating cross-view lines in SwiftUI
//
// ContentView.swift
// SwiftUIPlayground
//
// Created by BJ Homer on 4/26/21.
//
import SwiftUI
struct MainView: View {
var body: some View {
VStack {
Row()
Divider()
Row()
Divider()
Row()
}
.frame(width: .infinity)
.padding(20)
.overlayPreferenceValue(CircleCenterPreferenceKey.self) { anchors in
GeometryReader { geometry in
// We're going to take each adjacent pair of anchors and draw
// a line between them
let lines = zip(anchors, anchors.dropFirst()).map { anchors in
return line(for: geometry, anchors: anchors)
}
ForEach(lines, id: \.id) { $0.view }
}
}
}
func line(for geometry: GeometryProxy, anchors: (Anchor<CGPoint>, Anchor<CGPoint>)) -> (id: UUID, view: some View) {
var a = geometry[anchors.0]
var b = geometry[anchors.1]
// Put the top of the line a bit below the top anchor
a.y += 10
// Put the bottom of the line a bit above the bottom anchor
b.y -= 10
var path = Path()
path.move(to: a)
path.addLine(to: b)
// Using a UUID here is a little hacky… but it works for the demo
let id = UUID()
let view = path.stroke(Color.green, lineWidth: 3)
return (id, view)
}
}
struct Row: View {
var body: some View {
HStack {
DoubleCircle()
.anchorPreference(key: CircleCenterPreferenceKey.self,
value: .center, transform: { [$0] })
.frame(width: 40)
.foregroundColor(Color.gray)
Text("This is some very long text, which I would like to wrap")
Spacer()
}
}
}
struct DoubleCircle: View {
var body: some View {
ZStack {
Circle().frame(width: 6, height: 6)
Circle()
.stroke(lineWidth: 2)
.frame(width: 12, height: 12)
}
}
}
struct CircleCenterPreferenceKey: PreferenceKey {
static var defaultValue: [Anchor<CGPoint>] = []
static func reduce(value: inout Value, nextValue: () -> Value) {
value.append(contentsOf: nextValue())
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
MainView()
}
}
@bjhomer
Copy link
Author

bjhomer commented Aug 26, 2022

Screenshot 2022-08-26 at 7 22 24 AM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment