You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI列表圆点虚线连接求助:线条未衔接及首元素无上线条

SwiftUI 列表圆点虚线连接问题修复

问题说明

我正尝试在SwiftUI中创建一个列表,用虚线连接两个圆点。目前已经成功画出圆形和线条,但遇到两个问题:

  • 线条无法正确衔接
  • 列表的第一个圆点没有向上延伸的线条

修改方案

核心调整点:

  1. 给圆点组件添加索引判断参数,控制顶部/底部线条的显示
  2. 调整线条与圆形的布局尺寸,确保完美衔接
  3. 为线条添加虚线样式

修改后的完整代码

ScrollView {
    LazyVStack(spacing: 0) { // 移除列表项间距避免线条间隙
        ForEach(0 ..< 4, id: \.self) { index in
            HStack(alignment: .top, spacing: 10) {
                ConnectedCircles(isFirst: index == 0, isLast: index == 3)
                CardView_beige {
                    CardView_todo(title: "08:10 - 8:15", subtitle: "Mac Book sauber machen!", textlong: "15 min")
                }
                .padding(.vertical)
            }
        }
    }
    .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 {
    let isFirst: Bool
    let isLast: Bool
    let circleSize: CGFloat = 30
    let lineWidth: CGFloat = 4
    
    var body: some View {
        VStack(spacing: 0) {
            // 顶部线条:仅非第一个列表项显示
            if !isFirst {
                VerticalLine()
                    .stroke(style: StrokeStyle(lineWidth: lineWidth, dash: [8, 4])) // 设置虚线样式
                    .frame(width: lineWidth, height: circleSize/2) // 高度匹配圆形半径,保证衔接
                    .foregroundColor(.blue)
            }
            
            Circle()
                .strokeBorder(Color.blue, lineWidth: lineWidth)
                .frame(width: circleSize, height: circleSize)
            
            // 底部线条:仅非最后一个列表项显示
            if !isLast {
                VerticalLine()
                    .stroke(style: StrokeStyle(lineWidth: lineWidth, dash: [8, 4]))
                    .frame(width: lineWidth, height: circleSize/2)
                    .foregroundColor(.blue)
            }
        }
        .alignmentGuide(.top) { d in d[.top] } // 统一顶部对齐,保证列表项垂直排列整齐
    }
}

// CardView 组件优化(可选调整)
struct CardView_todo: View {
    var title: String
    var subtitle: String
    var textlong: String
    var time: String?
    
    var body: some View {
        VStack(alignment: .leading, spacing: 4) { // 调整布局间距更紧凑
            Text(title)
                .foregroundStyle(.black)
            Text(subtitle)
                .fontWeight(.bold)
                .foregroundStyle(.black)
            Text(textlong)
                .foregroundStyle(.black)
        }
    }
}

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)))
            .cornerRadius(10)
    }
}

关键调整解释

  • 线条显示逻辑:通过isFirst和isLast参数精准控制线条显示,避免第一个项出现顶部线条、最后一个项出现底部线条
  • 衔接精度优化:将线条高度设置为圆形半径,让线条刚好连接到圆形边缘,彻底解决衔接间隙问题
  • 虚线样式实现:使用StrokeStyle配置虚线的线段长度和间隔,满足需求
  • 布局对齐:设置HStack顶部对齐,确保所有列表项的圆点和卡片垂直对齐整齐

内容的提问来源于stack exchange,提问作者Jojo Who

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:25:29