3

I've developed this component in SwiftUI:

let rows: [RowModel] = [RowModel(type: "single",
                                 field: "single line field",
                                 value: "Value 1"),
                        RowModel(type: "multiple",
                                 field: "multiline field",
                                 value: "This is a multiline field and shoul use 2 or more lines"),
                        RowModel(type: "single",
                                 field: "single line field",
                                 value: "Value 2")]
InfoBlock(rows: rows)
    .padding([.leading, .trailing], 25)
    .padding(.bottom, 8)


struct InfoBlock: View {
    
    var rows: [RowModel]
    
    init(rows: [RowModel]) {       
        self.rows = rows
    }

    var body: some View {
        
        VStack(alignment: .leading, spacing: 0) {
            
            ForEach(0..<self.rows.count, id: \.self) {
                
                let row = self.rows[$0]
                let rowType = row.getType()
                if rowType == "single" {
                    InfoSingleRow(row)
                } else if rowType == "multiple" {
                    InfoMultipleRow(row)
                }
                
                if $0 < self.rows.count - 1 {
                    
                    Rectangle()
                        .fill(Color("grey40"))
                        .frame(height: 2)
                }
            }
        }
        .background(Color.clear)
        .overlay(RoundedRectangle(cornerRadius: 20)
                        .stroke(Color("grey40"), lineWidth: 1)
                )
    }
}

struct InfoSingleRow: View {

    private var row: RowModel

    init(_ row: RowModel) {
        self.row = row
    }

    var body: some View {
        
        HStack(spacing: 0) {
            
            Text(row.getField())
                .font(.uilight16)
                .foregroundColor(Color("primary3_primary2"))
                .multilineTextAlignment(.leading)
            
            Spacer()
            
            Text(row.getValue())
                .font(.uibook16)
                .foregroundColor(Color("primary3_primary2"))
                .lineLimit(1)
                .multilineTextAlignment(.trailing)
        }
        .padding([.top, .bottom], 15)
        .padding([.leading, .trailing], 13)
    }
}

struct InfoMultipleRow: View {

    private var row: RowModel

    init(_ row: RowModel) {
        self.row = row
    }

    var body: some View {
        
        HStack(spacing: 0) {
            
            Text(row.getField())
                .font(.uilight16)
                .foregroundColor(Color("primary3_primary2"))
                .multilineTextAlignment(.leading)
            
            Spacer()
            
            Text(row.getValue())
                .font(.uibook16)
                .foregroundColor(Color("primary3_primary2"))
                .multilineTextAlignment(.trailing)
        }
        .padding([.top, .bottom], 15)
        .padding([.leading, .trailing], 13)
    }
}

This produces the following output:

enter image description here

This is OK but I would like the fields to take 60% of the component width and the value the 40%. To do this I've tried to use GeometryReader:

struct InfoBlock: View {
    
    var rows: [RowModel]
    
    init(rows: [RowModel]) {
        self.rows = rows
    }

    var body: some View {
        
        VStack(alignment: .leading, spacing: 0) {
            
            ForEach(0..<self.rows.count, id: \.self) {
                
                let row = self.rows[$0]
                let rowType = row.getType()
                if rowType == "single" {
                    InfoSingleRow(row)
                } else if rowType == "multiple" {
                    InfoMultipleRow(row)
                }
                
                if $0 < self.rows.count - 1 {
                    
                    Rectangle()
                        .fill(Color("grey40"))
                        .frame(height: 2)
                }
            }
        }
        .background(Color.clear)
        .overlay(RoundedRectangle(cornerRadius: 20)
                        .stroke(Color("grey40"), lineWidth: 1)
                )
    }
}

struct InfoSingleRow: View {

    private var row: RowModel

    init(_ row: RowModel) {
        self.row = row
    }

    var body: some View {
        
        let horizontalPadding: CGFloat = 13.0
        GeometryReader { proxy in
            
            HStack(spacing: 0) {
                
                Text(row.getField())
                    .frame(width: (proxy.size.width - 2 * horizontalPadding) * 0.6, alignment: .leading)
                    .font(.uilight16)
                    .foregroundColor(Color("primary3_primary2"))
                    .multilineTextAlignment(.leading)
                
                Text(row.getValue())
                    .frame(width: (proxy.size.width - 2 * horizontalPadding) * 0.4, alignment: .trailing)
                    .font(.uibook16)
                    .lineLimit(1)
                    .foregroundColor(Color("primary3_primary2"))
                    .multilineTextAlignment(.trailing)
            }
            .padding([.leading, .trailing], horizontalPadding)
            .padding([.top, .bottom], 15)
        }
    }
}

struct InfoMultipleRow: View {

    private var row: RowModel

    init(_ row: RowModel) {
        self.row = row
    }

    var body: some View {
        
        let horizontalPadding: CGFloat = 13.0
        GeometryReader { proxy in
            
            HStack(spacing: 0) {
                
                Text(row.getField())
                    .frame(width: (proxy.size.width - 2 * horizontalPadding) * 0.6, alignment: .leading)
                    .font(.uilight16)
                    .foregroundColor(Color("primary3_primary2"))
                    .multilineTextAlignment(.leading)
                
                Text(row.getValue())
                    .frame(width: (proxy.size.width - 2 * horizontalPadding) * 0.4, alignment: .trailing)
                    .font(.uibook16)
                    .foregroundColor(Color("primary3_primary2"))
                    .multilineTextAlignment(.trailing)
            }
            .padding([.leading, .trailing], horizontalPadding)
            .padding([.top, .bottom], 15)
        }
    }
}

But, as you can see, the output doesn't respect the height:

enter image description here

So I've tried to set the top/bottom paddings to the GeometryReader:

struct InfoBlock: View {
    
    var rows: [RowModel]
    
    init(rows: [RowModel]) {
        self.rows = rows
    }

    var body: some View {
        
        VStack(alignment: .leading, spacing: 0) {
            
            ForEach(0..<self.rows.count, id: \.self) {
                
                let row = self.rows[$0]
                let rowType = row.getType()
                if rowType == "single" {
                    InfoSingleRow(row)
                } else if rowType == "multiple" {
                    InfoMultipleRow(row)
                }
                
                if $0 < self.rows.count - 1 {
                    
                    Rectangle()
                        .fill(Color("grey40"))
                        .frame(height: 2)
                }
            }
        }
        .background(Color.clear)
        .overlay(RoundedRectangle(cornerRadius: 20)
                        .stroke(Color("grey40"), lineWidth: 1)
                )
    }
}

struct InfoSingleRow: View {

    private var row: RowModel

    init(_ row: RowModel) {
        self.row = row
    }

    var body: some View {
        
        let horizontalPadding: CGFloat = 13.0
        GeometryReader { proxy in
            
            HStack(spacing: 0) {
                
                Text(row.getField())
                    .frame(width: (proxy.size.width - 2 * horizontalPadding) * 0.6, alignment: .leading)
                    .font(.uilight16)
                    .foregroundColor(Color("primary3_primary2"))
                    .multilineTextAlignment(.leading)
                
                Text(row.getValue())
                    .frame(width: (proxy.size.width - 2 * horizontalPadding) * 0.4, alignment: .trailing)
                    .font(.uibook16)
                    .lineLimit(1)
                    .foregroundColor(Color("primary3_primary2"))
                    .multilineTextAlignment(.trailing)
            }
            .padding([.leading, .trailing], horizontalPadding)
        }
        .padding([.top, .bottom], 15)
    }
}

struct InfoMultipleRow: View {

    private var row: RowModel

    init(_ row: RowModel) {
        self.row = row
    }

    var body: some View {
        
        let horizontalPadding: CGFloat = 13.0
        GeometryReader { proxy in
            
            HStack(spacing: 0) {
                
                Text(row.getField())
                    .frame(width: (proxy.size.width - 2 * horizontalPadding) * 0.6, alignment: .leading)
                    .font(.uilight16)
                    .foregroundColor(Color("primary3_primary2"))
                    .multilineTextAlignment(.leading)
                
                Text(row.getValue())
                    .frame(width: (proxy.size.width - 2 * horizontalPadding) * 0.4, alignment: .trailing)
                    .font(.uibook16)
                    .foregroundColor(Color("primary3_primary2"))
                    .multilineTextAlignment(.trailing)
            }
            .padding([.leading, .trailing], horizontalPadding)
        }
        .padding([.top, .bottom], 15)
    }
}

The output is better:

enter image description here

But, as you can see, the multiline row only takes 1 line, it doesn't takes its full height.

What could I try?

Wonton
  • 1,033
  • 16
  • 33

0 Answers0