Search code examples
swiftuimenudropdown

SwiftUI Menu Dropdown Appearance


I'm currently learning swift, swiftui and other components and I am stuck with the appearance of the buttons in the menu. I have an add Button at the top bar which appears as a sheet. When the menu button is pressed, the buttons from this menu are appearing at the top. I left space below and my question is, can I change the appearance of the buttons from the top to the bottom?

This is the ui of the app:

Image of the ui

My Code looks like this ->

This is the view which appears as sheet:

struct EinkaufAddView: View {
    
    @State var artikelTextField: String = ""
    @State var anzahlTextField: String = ""
    @State var kategorieNamen: String = "Kategorie"
    
    var body: some View {
        NavigationStack {
            
            VStack {
                HStack {
                    VStack {
                        Section("Produkt") {
                            TextField("Hinzufügen...", text: $artikelTextField)
                                .frame(width: 200, height: 50)
                                .padding(.horizontal)
                                .background(Color.gray.opacity(0.3).cornerRadius(10))
                                .padding(.horizontal)
                        }
                    }
                    
                    VStack {
                        Section("Anzahl") {
                            TextField("0", text: $anzahlTextField)
                                .keyboardType(.numberPad)
                                .frame(height: 50)
                                .frame(maxWidth: .infinity)
                                .padding(.horizontal)
                                .background(Color.gray.opacity(0.3).cornerRadius(10))
                                .padding(.horizontal)
                        }
                    }
                }
                .padding(.bottom, 20)
                
                Section("Kategorie") {
                    Menu(kategorieNamen) {
                        Button("Obst") {
                            kategorieNamen = "Obst"
                        }
                        Button("Milchprodukte") {
                            kategorieNamen = "Obst"
                        }
                        Button("Fleisch") {
                            kategorieNamen = "Obst"
                        }
                        Button("Getränke") {
                            kategorieNamen = "Obst"
                        }
                    }
                    .frame(height: 50)
                    .frame(maxWidth: .infinity)
                    .padding(.horizontal)
                    .background(Color.gray.opacity(0.3).cornerRadius(10))
                    .padding(.horizontal)
                }
            }
            .padding(.top, 30)
            
            Spacer()
            
            Button(action: {
                
            }, label: {
                Text("Produkt hinzufügen")
                    .foregroundStyle(.white)
                    .font(.title2)
                    .bold()
                    .frame(height: 50)
                    .frame(maxWidth: .infinity)
                    .background(Color.blue.cornerRadius(25))
            })
            .padding()
            
            .navigationTitle("Artikel hinzufügen")
        }
    }
}

#Preview {
    EinkaufAddView()
}

This is the view with the .sheet appearance:

struct Einkaufsliste: View {
    
    @State var showSheet: Bool = false
    @StateObject var vm = EinkaufViewModel()
    let kategorien: [Kategorie] = [
        Kategorie(title: "Obst", titleColor: Color.yellow, anzahl: 5),
        Kategorie(title: "Fleisch", titleColor: Color.purple, anzahl: 2),
        Kategorie(title: "Milchprodukte", titleColor: Color.blue, anzahl: 10),
        Kategorie(title: "Getränke", titleColor: Color.green, anzahl: 8)
    ]
    
    var body: some View {
        NavigationStack {
            ScrollView {
                HStack {
                    VStack {
                        ForEach(kategorien) { item in
                            NavigationLink {
                                EinkaufslisteDetailView(vm: vm, kategorieName: item.title)
                            } label: {
                                EinkaufsListView(kategorieNamen: item.title, anzahlKategorien: item.anzahl)
                            }
                            .buttonStyle(.plain)
                            .foregroundStyle(item.titleColor)
                        }
                    }
                }
            }
            .navigationBarItems(
                trailing: Button(action: { showSheet.toggle() }, label: {
                    Image(systemName: "plus.circle")
                        .resizable()
                        .frame(width: 30, height: 30)
                })
                .sheet(isPresented: $showSheet) {
                    EinkaufAddView()
                        .presentationDetents([.fraction(0.8)])
                }
            )
            .navigationTitle("Einkaufsliste 🍎")
        }
    }
}

#Preview {
    Einkaufsliste()
}

struct EinkaufsListView: View {
    
    let kategorieNamen: String
    let anzahlKategorien: Int
    
    var body: some View {
        ZStack() {
            RoundedRectangle(cornerRadius: 15)
                .stroke()
            
            HStack {
                Image(systemName: "apple.logo")
                    .padding(.horizontal)
                
                Spacer()
                
                Text(kategorieNamen)
                
                Spacer()
                
                ZStack {
                    RoundedRectangle(cornerRadius: 10)
                        .stroke()
                        .frame(width: 40, height: 40)
                    Text("\(anzahlKategorien)")
                }
                
                Image(systemName: "arrow.right")
                    .padding()
            }
        }
        .font(.title2)
        .fontWeight(.bold)
        .frame(width: 350, height: 60)
        .background(Color.gray.opacity(0.5).cornerRadius(15))
        .padding(.top)
    }
}

Please ignore the rest of the code, it is a total mess 😅.

I have looked at the internet but couldn't find anything useful. I think I heard somewhere that this cannot be changed, but I am still asking maybe I'm wrong.


Solution

  • When I started with Swift UI back then, I was also happy about every idea, hence my suggestion,

    I would create an array from the options (makes the code a bit easier and is super easy to maintain)

    let kategorien = ["Obst", "Milchprodukte", "Fleisch", "Getränke"]
    

    And you need a state variable that contains the current state:

    @State private var ausgewaehlt = "Obst"
    

    Here the Picker:

       Section("Kategorie") {
                        Picker("Kategorie", selection: $ausgewaehlt) {
                            ForEach(kategorien, id: \.self) {
                                Text($0)
                            }
                            
                        }
                        .pickerStyle(WheelPickerStyle())
                        .frame(height: 150)
                        .frame(maxWidth: .infinity)
                        .padding(.horizontal)
                        .background(Color.gray.opacity(0.1).cornerRadius(10))
                        .padding(.horizontal)
                                
                    }
    

    The picker uses the variable selected for the currently selected option and lists all categories. As the picker uses binding, the changes after each change in saved to the state variable.