1
votes

I would like to get the frame of a view in a LazyVStack. The LazyVStack embedded in a ScrollView displays chat messages (Text and Images).

Because the content is dynamically sized I am not able to use a GeometryReader Proxy. Putting a GeometryReader in my LazyVStack breaks the layout. ( I assume because of the dynamic sizing. ).

Is there any other way to get the frame of the views in the LazyVStack?

Below is a simple representation of what I want to do. Ideally I would like to have a GeometryReader in the MessageView but that messes up the vertical spacing.

struct ChatView: View {
    var body: some View {
        GeometryReader { geometry in
            ScrollView {
                LazyVStack {
                    ForEach(messages, id: \.id) { message in
                        MessageView(message: message)
                    }
                }
            }
        }
    }
}

struct MessageView: View {
    
    var message: Message
    
    var body: some View {
        // GeometryReader here is not possible with dynamic row heights
        if message.text != nil {
            Text(message.text!)
        } else if message.imageData != nil {
            Image(uiImage: UIImage(data: message.imageData!))  // <-- Get frame of this Image
        }
    }
}

Combining the MessageView into the ChatView is not desirable because the MessageView is quite involved with many views and needs to be an independent struct.

1

1 Answers

1
votes

You need to use GeometryReader in background of view which frame you want to measure, like

var body: some View {
    if message.text != nil {
        Text(message.text!)
    } else if message.imageData != nil {
        Image(uiImage: UIImage(data: message.imageData!))
          .background(GeometryReader { gp in
             // gp.frame(in: .global)   // << eg. frame in global coordinates
          })
    }
}

See also https://stackoverflow.com/a/62466397/12299030