简体   繁体   中英

How to align with a certain view in a VStack?

I'm trying to achieve the following layout:

预期布局

As you can see, Foo is aligned with Bar horizontally, and there's a vertical line at the bottom of Foo .

I haven't managed to do it, the best I can do is the following one:

我的布局

Here is the corresponding code:

import SwiftUI

struct ContentView: View {

    var body: some View {
        HStack {
            VStack(spacing: 5) {
                Text("Foo")
                    .padding(.bottom, 0)
                getVerticalLine()
            }
            Text("Bar")
                .padding(10)
                .frame(maxWidth: .infinity, alignment: .leading)
                .background(.yellow)
        }
        
    }
    
    private func getVerticalLine() -> some View {
        return Color.gray
            .frame(width: 1, height: 30)
            .padding(.leading, 0)
    }

}

My question is: how to modify the code to achieve the expected layout?

PS In the end, I want to achieve something like this:

最终期待

Here is the complete code that you want. You need to use multiplier for constant so that it fits in all devices.

CententView

struct ContentView: View {

    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            FooBarView(isLastOne: false)
                .padding(EdgeInsets(top: 0, leading: 10, bottom: -18, trailing: 0))
            FooBarView(isLastOne: false)
                .padding(EdgeInsets(top: 0, leading: 10, bottom: -18, trailing: 0))
            FooBarView(isLastOne: false)
                .padding(EdgeInsets(top: 0, leading: 10, bottom: -18, trailing: 0))
            FooBarView(isLastOne: true)
                .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 0))
        }
    }
}

FooBarView

struct FooBarView: View {
    var isLastOne: Bool
    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            HStack {
                VStack(spacing: 5) {
                    Text("Foo")
                        .padding(.bottom, 0)
                }
                Text("Bar")
                    .padding(10)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .background(.yellow)
            }
            if !isLastOne {
                getVerticalLine()
                    .padding(EdgeInsets(top: -5, leading: 12, bottom: 0, trailing: 0))
            }
        }
    }
    
    private func getVerticalLine() -> some View {
        return Color.gray
            .frame(width: 1, height: 40)
            .padding(.leading, 0)
    }
}

在此处输入图像描述

Each of your activities are a single HStack , with the time on the left. The line is just something that connects each row, not necessarily part of the row itself.

You can use a ZStack to show the gray line on the back and the rows on the front; a background on the first column will avoid overlapping the gray line.

The alignment is assured by giving the same frame width to the first column (time) and the vertical line.

Here's an example:

struct Example: View {
    
    struct Activity: Hashable, Identifiable {
        let id = UUID()
        let time: String
        let activity: String
    }
    
    let activities = [Activity(time: "10.00", activity: "Exercise"),
                      Activity(time: "11.00", activity: "Work"),
                      Activity(time: "12.00", activity: "Study"),
                      Activity(time: "13.00", activity: "Coding")]
    
    let firstColumnWidth = 80.0
    let spacingBetweenLines = 30.0
    let internalPadding = 10.0
    let lineHeight = 20.0

    var body: some View {
        
        ZStack {
            HStack {
                getVerticalLine
                    .frame(width: firstColumnWidth)
                Spacer()
            }
            
            VStack(spacing: spacingBetweenLines) {
                ForEach(activities) { item in
                    HStack(spacing: 5) {
                        Text(item.time)
                            .frame(height: lineHeight)
                            .padding(internalPadding)
                            .frame(width: firstColumnWidth)
                            .background(.white)
                        Text(item.activity)
                            .frame(height: lineHeight)
                            .padding(internalPadding)
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .background(.yellow)
                    }
                }
            }
        }
        .padding()
    }
    
    private var verticalLine: some View {
        let lineHeight = internalPadding * 2 + lineHeight + spacingBetweenLines
        return Color.gray
            .frame(width: 1, height: lineHeight * Double(activities.count - 1))
            .background(.green)
    }
}

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM