netshark1000
netshark1000

Reputation: 7413

SwiftUI: Spacing between List Items

I have some code that displays a list with a title and a rectangle and if the user taps on it, it navigates to a detail page.

But my code seems to have multiple problems:

  1. The spacer is not working. I want the name on the left and the rectangle on the right like a spacer in a Stack would push it.
  2. The background color of the rectangle is not applied. It is just black
  3. If I add a navigationTitle, I see constraint errors (see below)

( "<NSLayoutConstraint:0x600002438f50 'BIB_Trailing_CB_Leading' H:[_UIModernBarButton:0x7fd15fe088b0]-(6)-[_UIModernBarButton:0x7fd15fe064d0'World Clock'] (active)>", "<NSLayoutConstraint:0x600002438fa0 'CB_Trailing_Trailing' _UIModernBarButton:0x7fd15fe064d0'World Clock'.trailing <= _UIButtonBarButton:0x7fd15fe05310.trailing (active)>", "<NSLayoutConstraint:0x600002439d10 'UINav_static_button_horiz_position' _UIModernBarButton:0x7fd15fe088b0.leading == UILayoutGuide:0x600003e04a80'UIViewLayoutMarginsGuide'.leading (active)>", "<NSLayoutConstraint:0x600002439d60 'UINavItemContentGuide-leading' H:[_UIButtonBarButton:0x7fd15fe05310]-(0)-[UILayoutGuide:0x600003e049a0'UINavigationBarItemContentLayoutGuide'] (active)>", "<NSLayoutConstraint:0x6000024350e0 'UINavItemContentGuide-trailing' UILayoutGuide:0x600003e049a0'UINavigationBarItemContentLayoutGuide'.trailing == _UINavigationBarContentView:0x7fd15fd0a640.trailing (active)>", "<NSLayoutConstraint:0x60000243a4e0 'UIView-Encapsulated-Layout-Width' _UINavigationBarContentView:0x7fd15fd0a640.width == 0 (active)>", "<NSLayoutConstraint:0x6000024354a0 'UIView-leftMargin-guide-constraint' H:|-(0)-UILayoutGuide:0x600003e04a80'UIViewLayoutMarginsGuide' (active, names: '|':_UINavigationBarContentView:0x7fd15fd0a640 )>" )

enter image description here

Here is my code:

    var body: some View {
    NavigationView {
        
        List {
            ForEach(viewModel.cityList, id: \.name) { city in
                NavigationLink(
                    destination: CityDetailView(city: city)){
                    HStack{
                        Text(city.name)
                        Spacer()
                        CustomView()
                    }
                }.frame(height: 100)
            }
        }
        .navigationTitle("World Clock")
    }
}

    CustomView:
        var body: some View {
            GeometryReader { geo in
                Circle().frame(width: geo.size.height, height: geo.size.height)
                .background(Color.green)
            }
        }

Any idea what is wrong?

Upvotes: 1

Views: 2937

Answers (1)

Phil Dukhov
Phil Dukhov

Reputation: 88192

Your spacer doesn't work because there's NavigationLink in the HStack which took all the space: it has bigger priority than Spacer.

If you wanna use NavigationLink with EmptyView, it should be placed in a ZStack with nearby view, but in this case you can simply place content of your cell inside NavigationLink label.

Rectangle is not a view but a Shape, and as with any other Shape its color should be set with foregroundColor, not with background.

GeometryReader always takes all available space, unless you're adding size modifiers to it. It cannot wrap around content by itself. So you can use following trick: add onAppear for an item inside GeometryReader and pass width to state variable, which will then add width modifier to GeometryReader.

struct ContentView: View {
    @ObservedObject var viewModel = CityListViewModel()

    
    var body: some View {
        NavigationView {
            List {
                ForEach(viewModel.cityList, id: \.name) { city in
                    NavigationLink(
                        destination: Text(city.name)){
                        HStack{
                            Text(city.name)
                            Spacer()
                            CustomView()
                        }
                    }.frame(height: 100)
                }
            }
            .navigationTitle("World Clock")
        }
    }
}

struct CustomView: View {
    @State
    var width: CGFloat?
    
    var body: some View {
        GeometryReader { geo in
            Circle().frame(width: geo.size.height, height: geo.size.height)
                .background(Color.green)
                .onAppear {
                    width = geo.size.height
                }
        }.frame(width: width)
    }
}

If you see some NSLayoutConstraint broken which you didn't create, like when using SwiftUI, you can ignore it: it's not your bug.

Upvotes: 0

Related Questions