abdulqgg
abdulqgg

Reputation: 115

SwiftUI How to add done button to picker

Ive make a mini app with just a button and a picker and the idea is to have a done button above the picker so once ive chosen a value i can press done and the picker will close.

I am aware if you click the "click me" button it will open and if you click it again close the picker but im looking for a button that appears with the picker and disapears with the clicker when clicked.

Almost like a toolbar above the picker with a done button

    @State var expand = false
    @State var list = ["value1", "value2", "value3"]
    @State var index = 0

    var body: some View {
       VStack {
            Button(action: {
                self.expand.toggle()
            }) {
                Text("Click me \(list[index])")
            }
            if expand {
                Picker(selection: $list, label: EmptyView()) {
                    ForEach(0 ..< list.count) {
                        Text(self.list[$0]).tag($0)
                    }
                }.labelsHidden()
            }

        }

enter image description here

enter image description here enter image description here

The third image is what im trying to accomplish and the first 2 are what ive currently got

Thank you for your help

Upvotes: 4

Views: 9823

Answers (4)

Dirk Bester
Dirk Bester

Reputation: 1945

struct ContentView: View {
    var colors = ["Red", "Green", "Blue"]
    @State private var selectedColor = 0

    var body: some View {
        NavigationView {
            Form {
                Section {
                    Picker(selection: $selectedColor, label: Text("Color")) {
                        ForEach(0 ..< colors.count) {
                            Text(self.colors[$0])
                        }
                    }
                }
            }
        }
    }
}

This has some form specific picker behavior where it opens up inline with no button hiding needed.

Upvotes: 0

Kasey
Kasey

Reputation: 414

Also this would work (especially if you're doing it outside of a Vstack)...

   // Toolbar for "Done"
    func createToolbar() {
        let toolBar = UIToolbar()
        toolBar.sizeToFit()

        // "Done" Button for Toolbar on Picker View
        let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: 
       self, action: #selector(PageOneViewController.dismissKeyboard))

        toolBar.setItems([doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true

        // Makes Toolbar Work for Text Fields
        familyPlansText.inputAccessoryView = toolBar
        kidsOptionText.inputAccessoryView = toolBar
        ethnicityText.inputAccessoryView = toolBar
        }

And be sure to call createToolbar() and you're done!

Upvotes: 2

Asperi
Asperi

Reputation: 258413

Here is an approach how I would do this... of course tuning is still possible (animations, rects, etc.), but the direction of idea should be clear

Demo of result:

enter image description here

Code:

struct ContentView: View {
    @State var expand = false
    @State var list = ["value1", "value2", "value3"]
    @State var index = 0

    var body: some View {
       VStack {
            Button(action: {
                self.expand.toggle()
            }) {
                Text("Click me \(list[index])")
            }
            if expand {
                Picker(selection: $index, label: EmptyView()) {
                    ForEach(0 ..< list.count) {
                        Text(self.list[$0]).tag($0)
                    }
                }.labelsHidden()
                .overlay(
                    GeometryReader { gp in
                        VStack {
                            Button(action: {
                                self.expand.toggle()
                            }) {
                                Text("Done")
                                    .font(.system(size: 42))
                                    .foregroundColor(.red)
                                    .padding(.vertical)
                                    .frame(width: gp.size.width)
                            }.background(Color.white)
                            Spacer()
                        }
                        .frame(width: gp.size.width, height: gp.size.height - 12)
                        .border(Color.black, width: 8)
                    }
                )
            }

        }
    }
}

Upvotes: 1

simibac
simibac

Reputation: 8610

Add a Button to the if-clause:

if expand {
    VStack{
        Button(action:{self.expand = false}){
            Text("Done")
        }
        Picker(selection: $list, label: EmptyView()) {
            ForEach(0 ..< list.count) {
                Text(self.list[$0]).tag($0)
            }
        }.labelsHidden()
    }
}

Upvotes: 6

Related Questions