This is my code:
ScrollView {
LazyVStack {
ForEach(0 ..< 4, id: \.self) { _ in // Index verwenden
HStack {
ConnectedCircles()
CardView_beige {
HStack {
CardView_todo(title: "08:10 - 8:15", subtitle: "Mac Book sauber machen!", textlong: "15 min")
}
}
.padding()
}
}
}
.background(Color.white.ignoresSafeArea())
.clipShape(
.rect(
topLeadingRadius: 25,
bottomLeadingRadius: 0,
bottomTrailingRadius: 0,
topTrailingRadius: 25
)
)
}
struct VerticalLine: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: rect.midX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
return path
}
}
struct ConnectedCircles: View {
var body: some View {
VStack(spacing: 0) {
VerticalLine()
.stroke(Color.blue, lineWidth: 4)
.frame(width: 20, height: 10)
Circle()
.strokeBorder(Color.blue, lineWidth: 4)
.frame(width: 30, height: 30)
VerticalLine()
.stroke(Color.blue, lineWidth: 4)
.frame(width: 20, height: 50)
}
}
}
These are my CardViews:
struct CardView_todo: View {
var title: String
var subtitle: String
var textlong: String
var time: String?
var body: some View {
VStack {
VStack {
HStack {
Text(title)
.foregroundStyle(.black)
.padding(2)
Spacer()
}
HStack {
Text(subtitle)
.fontWeight(.bold)
.foregroundStyle(.black)
Spacer()
}
.padding(.leading, 2)
HStack {
Text(textlong)
.foregroundStyle(.black)
.padding(2)
Spacer()
}
}
}
}
}
struct CardView_beige<Content: View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
content
.padding()
.background(Color(#colorLiteral(red: 0.9490196078, green: 0.9019607843, blue: 0.8470588235, alpha: 1))) // Beige Hintergrundfarbe
.cornerRadius(10)
}
}
I'm trying to make a list in SwiftUI where two points are connected by what is actually a dotted line.
I have managed to create a circle and a line, but I can't get the lines to connect, and I can't get the first circle of the list to have a line going upwards, for example.
The dashed line makes this problem a little complicated. If you try to draw each link separately then you can sometimes see that the sizes of the dashes are different where the sections come together.
It works better if you have one continuous dashed line going from top to bottom. The circles can then simply be drawn over it. This can be achieved with just the VerticalLine
shape and basic Circle
shapes, ConnectedCircles
is not needed.
Like this:
EDIT: Implementation changed from an HStack
with negative padding on the main content to a ZStack
with leading padding on the main content (it looks the same, but I think it's a bit cleaner).
EDIT2: Updated in response to comment to hide the dashed line above the first circle and below the last.
struct ContentView: View {
let nCards = 4
var body: some View {
ScrollView {
ZStack(alignment: .leading) {
// The dashed line from top to bottom
VerticalLine()
.stroke(style: .init(lineWidth: 4, dash: [7, 5]))
.frame(width: 60)
.foregroundColor(.blue)
LazyVStack {
ForEach(0..<nCards, id: \.self) { index in // Index verwenden
HStack(spacing: 0) {
Circle()
.stroke(lineWidth: 4)
.frame(width: 30, height: 30)
.foregroundColor(.blue)
.background(.white)
CardView_beige {
CardView_todo(title: "08:10 - 8:15", subtitle: "Mac Book sauber machen!", textlong: "15 min")
}
.padding()
}
// Align the circles with the dashed line
.padding(.leading, 15)
// Cover the dashed line above the first circle
// and below the last
.background {
if index == 0 {
VStack {
Color.white
Color.clear
}
} else if index == nCards - 1 {
VStack {
Color.clear
Color.white
}
}
}
}
}
}
.background(Color.white.ignoresSafeArea())
.clipShape(
.rect(
topLeadingRadius: 25,
bottomLeadingRadius: 0,
bottomTrailingRadius: 0,
topTrailingRadius: 25
)
)
}
}
}
Hope it's close to what you were wanting.