37

I want to create a dropdown-menu in Xcode 11 Beta 1. But i have not found a way to to it in iOS.

I have tried it with the .hidden function and found the PullDownButton, but don‘t know how to set it up

I have created this Code

struct SwiftUIView : View {
@State var array = true
@State var buttonTitle = "Zeige Deteils"

var body: some View {
    VStack {
        VStack {
            Button(action: {
                self.array.toggle()

            }) {
                Text(buttonTitle)
            }


            if array {
                VStack(spacing: 1.0) {

                    Button(action: {
                        self.buttonTitle = "Schmelzpunkt"
                        self.array.toggle()
                    }) {
                        Text("Schmelzpunkt")
                            .color(.white)
                            .padding(.all)
                    }
                    .background(Color.blue)
                    Button(action: {
                        self.buttonTitle = "Instrumentelle Analytik"
                        self.array.toggle()
                    }) {
                        Text("Instrumentelle Analytik")
                            .color(.white)
                            .padding(.all)
                            }.background(Color.blue)
                            Button(action: {
                                self.buttonTitle = "Aussehen"
                                self.array.toggle()
                            }) {
                                Text("Aussehen")
                                    .color(.white)
                                    .padding(.all)
                                    }.background(Color.blue)

                                }
                                .padding(.top)
                        }
                    }
                }
}

But can't find a was to animate the "poping-up" auf the hidden Buttons and want to the primary button to stay at its position

1
  • Could you please be more specific? Are you talking about iOS or macOS? Commented Jun 9, 2019 at 10:03

8 Answers 8

37

In SwiftUI 2.0 (iOS 14+) you can make a dropdown menu with Menu.

Menu {
    Button {
        // do something
    } label: {
        Text("Linear")
        Image(systemName: "arrow.down.right.circle")
    }
    Button {
        // do something
    } label: {
        Text("Radial")
        Image(systemName: "arrow.up.and.down.circle")
    }
} label: {
     Text("Style")
     Image(systemName: "tag.circle")
}
Sign up to request clarification or add additional context in comments.

3 Comments

Is there a way to increase width of items/tiles inside the menu? I can't seem to increase its width.
As far as I know, you can't. (Probably to keep consistency throughout the OS and maybe also to prevent devs from abusing them, or they just didn't think to add that feature).
what's the style = 0 \1 ? (it doesn't compile)
20

Using SwiftUI 2.0 you can also implement dropdown menu with DisclosureGroup here is ref.

GroupBox {
    DisclosureGroup("Menu 1") {
        Text("Item 1")
        Text("Item 2")
        Text("Item 3")
    }
}

Comments

11

You might want to take a look at the Picker.

struct ContentView : View {
    @State private var selection = 1
    var body: some View {
        VStack {
            Picker(selection: $selection, label: Text("Zeige Deteils")) {
                Text("Schmelzpunkt").tag(1)
                Text("Instrumentelle Analytik").tag(2)
            }
        }
    }
}

enter image description here

Comments

10

Many good answers but what worked for me was something custom but very similar to Menu in swiftui

So start by creating your item for dropdown view.

example.

import SwiftUI


struct SampleDropDown: View {
    
  
    let action : (String?) -> Void
    
    var body: some View {
        
        
        VStack(alignment: .leading, spacing: 4){
            
            ForEach(0...3, id: \.self){ valueStore in
                
                Button(action: {
                    
                    
                    
                }) {
                    
                    HStack(alignment: .center, spacing: 8) {
                        
                        Image(systemName: "bell")
                            .resizable()
                            .frame(width: 30, height: 30, alignment: .center)
                            .clipShape(Circle())
                        
                        VStack (alignment: .leading){
                            Text("ANDROID" )
                                .font(.custom(Constants.FONT_REGULAR, size: 14))
                                .foregroundColor(Color.fromHex(Colors.TEXT_COLOR_PRIMARY))
                                .padding([.leading, .top], 4)
                            
                            Text("#jetpack")
                                .font(.custom(Constants.FONT_REGULAR, size: 12))
                                .foregroundColor(Color.fromHex(Colors.LIGHT_GREY))
                                .padding([.leading, .bottom], 2)
                            
                        }
                        
                        
                    }.foregroundColor(Color.fromHex(Colors.LIGHT_GREY))
                    
                }.frame(width: .none, height: .none, alignment: .center)
                
                
                Divider().background(Color.fromHex(Colors.DIVIDOR))
                
            }
            
        }.padding(.all, 12)
        .background(RoundedRectangle(cornerRadius: 6).foregroundColor(.white).shadow(radius: 2))
        
    }
}

struct SampleDropDown_Previews: PreviewProvider {

    static var previews: some View {
        SampleDropDown(action: {data in}).padding()
    }
}

ui so far:

enter image description here

Now just add this as Overlay where you want to show or on top of which you want to show.

something like this.

example.

 @State var showStoreDropDown: Bool = false
  //ui 
 HStack(alignment: .center, spacing: 16) {
                    
                    //here you UI goes 
                    
                }.overlay (
                    
                    VStack {
                        
                        if showTimeframeDropDown {
                            
                            Spacer(minLength: 40)
                            
                            SampleDropDown(action: { data in
                                
                            })
                            
                        }
                        
                    }, alignment: .topLeading
                    
                ).onTapGesture {
                    
                    showTimeframeDropDown.toggle()
                    
                }

result :

enter image description here

Note: This is just a sample code from my project, please change accordingly but the basic idea is to have drop-down view as an overlay on the host view.

Comments

8

You need to use an overlay to display your dropdown. Otherwise, parents' layout will be wrong when you show and hide the dropdown.

demo

Here is a simple answer, and the complete answer could be found here

struct Dropdown: View {
    var options: [DropdownOption]
    var onSelect: ((_ key: String) -> Void)?

    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            ForEach(self.options, id: \.self) { option in
                DropdownOptionElement(val: option.val, key: option.key, onSelect: self.onSelect)
            }
        }

        .background(Color.white)
        .cornerRadius(dropdownCornerRadius)
        .overlay(
            RoundedRectangle(cornerRadius: dropdownCornerRadius)
                .stroke(Color.coreUIPrimary, lineWidth: 1)
        )
    }
}

struct DropdownButton: View {
    @State var shouldShowDropdown = false
    @Binding var displayText: String
    var options: [DropdownOption]
    var onSelect: ((_ key: String) -> Void)?

    let buttonHeight: CGFloat = 30
    var body: some View {
        Button(action: {
            self.shouldShowDropdown.toggle()
        }) {
            HStack {
                Text(displayText)
                Spacer()
                    .frame(width: 20)
                Image(systemName: self.shouldShowDropdown ? "chevron.up" : "chevron.down")
            }
        }
        .padding(.horizontal)
        .cornerRadius(dropdownCornerRadius)
        .frame(height: self.buttonHeight)
        .overlay(
            RoundedRectangle(cornerRadius: dropdownCornerRadius)
                .stroke(Color.coreUIPrimary, lineWidth: 1)
        )
        .overlay(
            VStack {
                if self.shouldShowDropdown {
                    Spacer(minLength: buttonHeight + 10)
                    Dropdown(options: self.options, onSelect: self.onSelect)
                }
            }, alignment: .topLeading
        )
        .background(
            RoundedRectangle(cornerRadius: dropdownCornerRadius).fill(Color.white)
        )
    }
}

1 Comment

How to set default Value ?
6
           Text("Options")
            .contextMenu {
                Button(action: {
                    // change country setting
                }) {
                    Text("Choose Country")
                }

                Button(action: {
                    // enable geolocation
                }) {
                    Text("Detect Location")
                }
            }

taken from https://www.hackingwithswift.com/quick-start/swiftui/how-to-show-a-context-menu Right click it to show the view

Comments

3

Most of the answers are good But everything needs to write from scratch. So I used a UIKit DropDown and create a UIViewRepresentable from it.

import SwiftUI
import DropDown

struct DropDownViewRepresentable: UIViewRepresentable {

  @Binding var selectedItem: String //Send Selected item
  @Binding var isActive: Bool //Hide and Show the Dropdown

  let dropDown = DropDown()

  func makeUIView(context: Context) -> UIView {
    let view = UIView(frame: .zero)
    return view
  }

  func updateUIView(_ uiView: UIView, context: Context) {
    
    // The view to which the drop down will appear on
    dropDown.anchorView = uiView // UIView or UIBarButtonItem
    
    // The list of items to display. Can be changed dynamically
    dropDown.dataSource = ["Car", "Motorcycle", "Truck"]
    dropDown.dismissMode = .manual
    
    dropDown.selectionAction = { (index: Int, item: String) in
      print("Selected item: \(item) at index: \(index)")
        selectedItem = item
        isActive = false
    }
    
    dropDown.direction = .bottom
    
    // Top of drop down will be below the anchorView
    dropDown.bottomOffset = CGPoint(x: 0, y:(dropDown.anchorView?.plainView.bounds.height)!)
    
    dropDown.cancelAction = {
        print("Drop down dismissed")
    }

    dropDown.willShowAction = {
        print("Drop down will show")
    }
    
    if isActive{
        dropDown.show()
    }else{
        dropDown.hide()
    }
   }
 }

Note: I just created it to access the basic features.

2 Comments

can you provide a sample how to use it
DropDownViewRepresentable(selectedItem: $selectedItem, isActive: $isActive)
2

Dropdown

import SwiftUI

struct DropdownView<Control, Dropdown>: View where Control: View, Dropdown: View {
    @State var show: Bool = true
    let control: () -> Control
    let dropdown: () -> Dropdown

    var body: some View {
        control() // <--(1)
            .opacity(show ? 0.7 : 1.0)
            .zIndex(1)
            .onTapGesture {
                show.toggle()
            }
            .overlay(alignment: .bottomLeading) {
                Group {
                    if show {
                        dropdown() // <--(2)
                            .transition(.opacity)
                    }
                }
                .alignmentGuide(.bottom) { $0[.top] }
            }
            .animation(.easeOut(duration: 0.2), value: show)
    }
}

// Preview Example:

struct DropdownView_Previews: PreviewProvider {
    static var previews: some View {
        VStack(alignment: .leading) {
            
            DropdownView { // <--(Use)
                Text("Dropdown")
                    .background(Color.red)
            } dropdown: {
                HStack {
                    VStack(alignment: .leading) {
                        Button("Menu item 1111") {}
                        Button("Menu item 2222") {}
                        Button("Menu item 3333") {}
                    }
                    Spacer()
                }
                //.frame(width: 140)
                .background(Color.gray)
            }
            
            Text("Lorem ipsum dolor") // example
        }
    }
}

Control limits the width of the dropdown menu:

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.