Last active
November 5, 2022 05:31
-
-
Save bjhomer/c1da7d1d689172dd21bc4795861df99d to your computer and use it in GitHub Desktop.
Creating cross-view lines in SwiftUI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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() | |
} | |
} | |
Author
bjhomer
commented
Aug 26, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment