基于单元格大小的可变 Rectangle() 维度绘制时间线

Variable Rectangle() dimension based on cell size to draw a timeline

我正在尝试构建一个看起来像时间轴的列表。 每个单元格代表一个里程碑。 在 table 的左侧,我希望单元格 'connected' 靠一条线(时间线)。 我已经尝试了各种方法让它按我想要的方式显示,但我已经解决了基本的几何形状,即 Circle() 和 Rectangle()。

这是突出问题的示例代码:

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        let roles: [String] = ["CEO", "CFO", "Managing Director and Chairman of the supervisory board", "Systems Analyst", "Supply Chain Expert"]
        NavigationView{
            VStack{
                List {
                    ForEach(0..<5) { toto in
                        NavigationLink(
                            destination: dummyView()
                        ) {
                            HStack(alignment: .top, spacing: 0) {
                                VStack(alignment: .center, spacing: 0){
                                    Rectangle()
                                        .frame(width: 1, height: 30, alignment: .center)
                                    Circle()
                                        .frame(width: 10, height: 10)
                                    Rectangle()
                                        .frame(width: 1, height: 20, alignment: .center)
                                    Circle()
                                        .frame(width: 30, height: 30)
                                        .overlay(
                                            Image(systemName: "gear")
                                                .foregroundColor(.gray)
                                                .font(.system(size: 30, weight: .light , design: .rounded))
                                                .frame(width: 30, height: 30)
                                        )
  //THIS IS THE RECTANGLE OBJECT FOR WHICH I WANT THE HEIGHT TO BE VARIABLE
                                    Rectangle()
                                        .frame(width: 1, height: 40, alignment: .center)
                                        .foregroundColor(.green)
                                }
                                .frame(width: 32, height: 80, alignment: .center)
                                .foregroundColor(.green)
                                
                                
                                VStack(alignment: .leading, spacing: 0, content: {
                                    Text("Dummy operation text that will be in the top of the cell")
                                        .font(.subheadline)
                                        .multilineTextAlignment(.leading)
                                        .lineLimit(1)
                                    Label {
                                        Text("March 6, 2021")
                                            .font(.caption2)
                                    } icon: {
                                        Image(systemName: "calendar.badge.clock")
                                    }
                                    
                                    HStack{
                                        
                                        HStack{
                                            Image(systemName: "flag.fill")
                                            Text("In Progress")
                                                .font(.system(size: 12))
                                        }
                                        .padding(.horizontal, 4)
                                        .padding(.vertical, 3)
                                        .foregroundColor(.blue)
                                        .background(Color.white)
                                        .cornerRadius(5, antialiased: true)
                                        
                                        HStack{
                                            Image(systemName: "person.fill")
                                            Text(roles[toto])
                                                .font(.system(size: 12))
                                            
                                        }
                                        .padding(.horizontal, 4)
                                        .padding(.vertical, 3)
                                        .foregroundColor(.green)
                                        .background(Color.white)
                                        .cornerRadius(5, antialiased: true)
                                        
                                        
                                        HStack{
                                            Image(systemName: "deskclock")
                                            Text("in 2 Months")
                                                .font(.system(size: 12))
                                        }
                                        .padding(.horizontal, 4)
                                        .padding(.vertical, 3)
                                        .foregroundColor(.red
                                            
                                        )
                                        .background(
                                            Color.white
                                        )
                                        .cornerRadius(5, antialiased: true)
                                    }
                                    
                                })
                            }.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
                        }
                    }
                }
            }
        }    
    }
}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct dummyView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

struct dummyView_Previews: PreviewProvider {
    static var previews: some View {
        dummyView()
    }
}

但是正如您在附上的图片中看到的那样,存在不需要的间隙

因此单元格中的其他内容使整个单元格的高度成为 'unpredictable' 并打破了线条。

有没有办法确定单元格的高度并扩展矩形的尺寸,使其延伸到单元格的整个高度?

您是否推荐了更好的方法来尝试构建这样的时间表?

PS:我试过使用 .frame 和 .infinity,但这确实有效。 非常感谢。

为什么不直接根据行的大小画线。参见 Creating custom paths with SwiftUI。记住,一切都是风景。

首先,你需要将你正在做的事情分解成子视图。您在一个视图中有太多移动部件以使其正确。另外,我会避免设置特定的填充量,因为这会在您更换设备时弄乱您。您想要一个简单、智能的视图,该视图足够通用以处理不同的设备。

我会有一个具有几何形状 reader 的行视图,因此它知道自己的高度。然后,您可以绘制这条线,使其跨越行的整个高度,而不管高度如何。类似这样的事情:

struct ListRow: View {
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                HStack {
                    Spacer()
                    Text("Hello, World!")
                    Spacer()
                }
                VerticalLine(geometry: geometry)
            }
        }
    }
}

struct VerticalLine: View {
    
    let geometry: GeometryProxy
    
    var body: some View {
        Path { path in
            path.move(to: CGPoint(x: 20, y: -30))
            path.addLine(to: CGPoint(x: 20, y: geometry.size.height+30))
        }
        .stroke(Color.green, lineWidth: 4)
    }
}