Oleg G.
Oleg G.

Reputation: 588

SwiftUI picker with a button in the navbar

On the track to learn more and more about SwiftUI. I come accross some weird behaviors.

I have a simple view called Modal. I am using a Picker in it and set a title in the navigation bar to go in the detail view.

That works fine. The problem starts when I add a button in the nav bar. It end up looking like this

Without the + button enter image description here

With the + button enter image description here

And the code is the following:

ContentView.swift

import SwiftUI

struct ContentView: View {
    @State var isShowing = false
    
    var body: some View {
        VStack(content: {
            Button("Modal") {
                isShowing = true
            }
        })
        .sheet(isPresented: $isShowing, content: content)
    }
    
    @ViewBuilder
    func content() -> some View {
        Modal()
    }
}

Modal.swift

import SwiftUI
import Combine

struct Modal: View {
    @State var selection: String = ""
    @State var list: [String] = ["1", "2", "3", "4", "5", "6"]
    
    var body: some View {
        NavigationView(content: {
            Form(content: {
                self.type()
            })
            .navigationBarTitle("Modal", displayMode: .inline)
        })
    }
}

private extension Modal {
    func type() -> some View {
        Section(content: {
            Picker(selection: $selection, label: Text("Type").bold()) {
                ForEach(list, id: \.self) { item in
                    Text(item)
                        .tag(UUID())
                }
                .navigationBarTitle("Select")
                .navigationBarItems(trailing: button())
            }
        })
    }
    
    func button() -> some View {
        HStack(alignment: .center, content: {
            Button(action: {
                // Action
            }) {
                Image(systemName: "plus")
            }
        })
    }
}

Upvotes: 2

Views: 1581

Answers (1)

Asperi
Asperi

Reputation: 257533

This is because .navigationBarItems modifier generates flat view from dynamic ForEach views, attach instead it to one view inside ForEach, like

    Section(content: {
        Picker(selection: $selection, label: Text("Type").bold()) {
            ForEach(list, id: \.self) { item in
                if item == list.last {
                   Text(item)
                      .navigationBarTitle("Select")
                      .navigationBarItems(trailing: button())
                      .tag(UUID())
                } else {
                   Text(item)
                      .tag(UUID())
                }
            }
        }
    })

Upvotes: 4

Related Questions