Home > Software engineering >  Dynamic view layout in SwiftUI
Dynamic view layout in SwiftUI

Time:10-29

I'm trying to implement the layout below in SwiftUI - a cell that can be used in VStack or List but I'm stuck. Is it possible to achieve this layout without Grid (I have to support iOS 15 )? enter image description here

CodePudding user response:

There is a solution, but the main issue is the alignment of both rows: to keep the top row (title and toggle) at the very top and the second row (text and status) at the very bottom, and keep it simple, its is necessary to fix the height of the view to a certain value.

If that can work for you, you can use 2 VStacks separated by a 20 pt spacer and embedded in an HStack. The example below fixes the height of the view to 70 pt.

var body: some View {
    HStack {
        
        VStack(alignment: .leading) {
            
            Text("Title")
//                Text("Title can be very, very big and not have enough space be be shown entirely")
                .font(.footnote)
                .lineLimit(1)
                .foregroundColor(.secondary)
            
            Spacer()
            
//                Text("Short text")
            Text("This text can have two lines and can also be shrinkable to make enough space for the toggle on the right")
                .multilineTextAlignment(.leading)
                .lineLimit(2)
                .layoutPriority(2)

        }
        .layoutPriority(1)
        
        Spacer(minLength: 20)
        
        VStack(alignment: .trailing) {
            Toggle(isOn: .constant(true)) {}
                .frame(alignment: .top)
            
            Spacer()
            
//                Text("On")
            Text("Status row can be a lot longer than you think")
                .font(.footnote)
                .lineLimit(1)
                .foregroundColor(.secondary)
                .frame(minWidth: 60, maxWidth: 100, alignment: .trailing)

        }
        
    }
    .frame(maxHeight: 70)

}

CodePudding user response:

Perhaps something like this (all styling for demonstration - didn't try to recreate the original post):

HStack(alignment: .lastTextBaseline, spacing: 20) {
    VStack(alignment: .leading) {
        Text("Title can have only one line, Title can have only one line")
            .font(.callout)
            .lineLimit(1)
        Text("This text can have 2 lines and can be shrinked")
            .font(.largeTitle)
            .lineLimit(2)
    }
    
    VStack(alignment: .trailing) {
        Toggle("", isOn: .constant(true))
            .labelsHidden()
        Spacer()
        Text("Longer Status text")
            .lineLimit(1)
            .frame(minWidth: 60, maxWidth: 100)
    }
}
.fixedSize(horizontal: false, vertical: true)
.padding()
.border(Color.secondary)

The key point here is the fixedSize modifier which essentially "hugs" the view vertically. Without that, the Spacer would expand the view vertically and claim all available space.

Seems to cover all the cases you have mentioned above:

enter image description here

  • Related