skip to Main Content

Let’s say I have the following layout:

VStack {
  Text(title)
    .frame(maxWidth: .infinity, alignment: .leading)

  Spacer()

  Divider()
    .frame(height: 1)
}
.frame(minHeight: 80, alignment: .bottom)

I want the text field to expand freely, divider to be aligned to the bottom, and the whole thing to be at least 80 points tall (but not taller if not necessary). If I leave it like this the spacer will take up all of the parent’s height (exceeding 80). If I don’t have a spacer, both subviews will be aligned together to the top, bottom, or center.

How can I achieve desired spacer behaviour? Or maybe the layout should be structured differently?

2

Answers


  1. If I understand correctly, you need a hight of 80 or more if needed, right?

    Since it depends on the text, why don’t you assign the minimum height to the Text itself and get rid of the Spacer?

    VStack(alignment: .leading) {
        Text(title)
            .frame(minHeight: 80)
            .lineLimit(0)
    
        Divider()
    }
    
    Login or Signup to reply.
  2. You can create any views and observe their content height/width using PreferenceKey. Depending on your request you might use different conditions, for example in my piece of code – viewHeight:

    struct ContentView: View {
        var title = "TitleTitleTitleTitle"
        @State private var textHeight: CGFloat = 0
        var viewHeight: CGFloat {
            if textHeight < 80 {
                return 80
            } else {
                return textHeight
            }
        }
        var body: some View {
            VStack {
                Text(title)
                    .fixedSize(horizontal: false, vertical: true)
                    .frame(alignment: .leading)
                    .background(
                        GeometryReader { geometry in
                            Color.clear
                                .preference(
                                    key: TextHeightKey.self,
                                    value: geometry.size.height
                                )
                        }
                    )
                
                Spacer()
                
                Divider()
                    .frame(height: 1)
            }
            .frame(height: viewHeight, alignment: .bottom)
            .onPreferenceChange(TextHeightKey.self) { height in
                textHeight = height
            }
        }
    }
    
    struct TextHeightKey: PreferenceKey {
        static var defaultValue: CGFloat = 0
        
        static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
            value = max(value, nextValue())
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search