swiftswiftuicategoriespickerswiftui-picker

SwiftUI Create Picker with possibility to add elements


I'm trying to build a swift app with categories, I created a Picker for my categories but I would like to be able to create a Category inside the Picker itself. But I can't figure how to do it properly, I've tried something sketchy but it's kinda ugly and working as I would like to do.

This is my working picker

import SwiftUI

struct CategoryPicker: View {
    @Binding var selection: TransactionCategory?
    @Binding var userData: UserData
    
    var body: some View {
        Picker("category", selection: $selection) {
            CategoryView(category: nil)
                .tag(nil as TransactionCategory?)
            ForEach(userData.transactionsCategories) { category in
                CategoryView(category: category)
                    .tag(category as TransactionCategory?)
            }
        }
    }
}

And this is what I tried so far but it's rendering pretty bad

struct CustomPickerExperiments: View {
    @Binding var selection: TransactionCategory?
    @Binding var userData: UserData
    @Environment(\.presentationMode) var presentation
    
    @State var color = Color.white
    @State var name = ""
    
    var body: some View {
        List {
            Section(header: Text("new-category")) {
                NavigationLink("add-category", destination: CategoryEditView(userData: $userData))
            }
            Section(header: Text("categories")) {
                CategoryView(category: nil)
                    .tag(nil as TransactionCategory?)
                    .onTapGesture {
                        if(selection != nil) {
                            selection = nil as TransactionCategory?
                            self.presentation.wrappedValue.dismiss()
                        }
                    }
                ForEach(userData.transactionsCategories) { category in
                    CategoryView(category: category)
                        .tag(category as TransactionCategory?)
                        .onTapGesture {
                            if(selection != category) {
                                selection = category as TransactionCategory?
                                self.presentation.wrappedValue.dismiss()
                            }
                        }
                }
            }
        }
    }
}

Solution

  • As commented not sure what you try to achieve.
    But as I understand it a Menu might be an easier way to go:

    struct ContentView: View {
        
        @State private var categories = [
            Category(name: "Beer"),
            Category(name: "Red Wine"),
            Category(name: "Water"),
            Category(name: "Juice")
        ]
        
        @State private var selection: Category?
        @State private var showingSheet = false
        @State private var newName = "New Category"
    
        
        var body: some View {
            VStack {
                Menu(selection?.name ?? "no selection") {
                    Button("New Category ...") {
                            showingSheet = true
                        }
    
                    ForEach(categories) { category in
                        Button(category.name) { selection = category }
                    }
                }
            }
            
            .sheet(isPresented: $showingSheet, onDismiss: {
                if !newName.isEmpty {
                    let newCat = Category(name: newName)
                    categories.append(newCat)
                    selection = newCat
                    newName = ""
                }
            }, content: {
                VStack(alignment: .leading) {
                    Text("Add Category").font(.headline)
                    TextField("New Name", text: $newName)
                }.padding()
            })
        }
        
        
        struct Category: Identifiable, Hashable {
            let id = UUID()
            var name: String
        }
    
    }