2
votes

I'm trying to position a ListView directly below a text field, using a ZStack and the field's geometry - its position and size. This is with a view toward creating an autocomplete picklist

Setting the offset only appears to half work.

So far it looks as follows.

Emulator and device appears as on the right:

enter image description here

Some useful information here:

https://swiftui-lab.com/geometryreader-to-the-rescue/

import SwiftUI

struct TestView: View {

    @State private var firstname = ""
    @State private var lastname = ""
    @State private var townCity = ""

    @State private var rect: CGRect = CGRect()

    var body: some View {
        ZStack (alignment: .topLeading){
            VStack{
                Form {
                    Section {
                        TextField("Firstname", text: $firstname)
                        TextField("Lastname", text: $lastname)

                        ZStack{
                            VStack (alignment: .leading, spacing: 0){
                                TextField("Town/City", text: self.$townCity)
                                    .background(GeometryGetterV2(rect: $rect))
                            }
                            .border(Color.black, width: 1)
                        }
                        Button("Save") {
                        }
                    }
                }
            }
            SelectionsPickerV2()
                .offset(x: rect.origin.x, y: rect.origin.y)
                //.offset(x: rect.minX, y: rect.minY)
                .frame(
                    width: rect.size.width,
                    height: rect.size.height * 7)
        }
        .coordinateSpace(name: "myZstack")
    }
}

struct SelectionsPickerV2: View {

    var body: some View {
        VStack (alignment: .leading) {
            List{
                Text("Sydney, Australia")
                Text("New York, New York")
                Text("London, UK")
                Text("Paris, France")
            }
            .background(Color.blue)
        }
        .border(Color.red, width: 1)
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
    }
}

struct GeometryGetterV2: View {
    @Binding var rect: CGRect

    var body: some View {
        return GeometryReader { geometry in
            self.makeView(geometry: geometry)
        }
    }

    func makeView(geometry: GeometryProxy) -> some View {
        DispatchQueue.main.async {
            self.rect = geometry.frame(in: .named("myZstack"))
            //self.rect = geometry.frame(in: .local)
            //self.rect = geometry.frame(in: .global)
        }

        return Rectangle().fill(Color.clear)
    }
}
2
@kontiki - Perhaps you've some magic here? - Yarm
Hi Craig, you forgot to include the code of your SelectionsPicker. Let me know when you post it. ;-) - kontiki
@kontiki - Now posted. Thanks - Yarm

2 Answers

0
votes

As many mentioned, your ZStack being the top level view gets geometry calculations wrong as the navigation bar gets added, etc. Probably just another SwiftUI bug.

To fix it just embed your ZStack inside a new parent view.

struct TestView: View {

    // ...

    var body: some View {
        VStack { // New parent view
            ZStack (alignment: .topLeading){
                // ...
            }
            SelectionsPickerV2()
                .offset(x: rect.origin.x, y: rect.origin.y)
                .frame(
                    width: rect.size.width,
                    height: rect.size.height * 7)
            }
            .coordinateSpace(name: "myZstack") // Fixed coordinate space
        }
    }
}
-1
votes

What Xcode version are you using, it looks nice with mine (Xcode 11.2, beta 11B41).

enter image description here