Reputation: 537
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
Upvotes: 37
Views: 62510
Reputation: 844
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:
Upvotes: 1
Reputation: 627
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")
}
Upvotes: 36
Reputation: 282
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.
Upvotes: 2
Reputation: 3480
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")
}
}
Upvotes: 19
Reputation: 11018
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:
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 :
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.
Upvotes: 10
Reputation: 91
You need to use an overlay to display your dropdown. Otherwise, parents' layout will be wrong when you show and hide the dropdown.
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)
)
}
}
Upvotes: 8
Reputation: 16700
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
Upvotes: 6
Reputation:
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)
}
}
}
}
Upvotes: 11