How can I add section footer text below SwiftUI Picker options?
Asked Answered
S

1

14

I’m writing an app on SwiftUI and I use Picker to present a list of options for the user to choose.

I’d like to add some footer text to explain the choices in the list when someone taps into the picker and sees the options.

This is an example screenshot of what I’d like to accomplish, taken from the iOS Settings app: AirDrop settings

How can I achieve this with SwiftUI?

I define a footer for the Section that contains the Picker on the main screen ("Here is a short description of the setting.") and that works fine, but similar code does not add a footer on the screen that shows the Picker options.

Here’s my example code:

import SwiftUI

class ViewModel: ObservableObject {

    enum Option: String, Identifiable, CaseIterable, CustomStringConvertible {
        case optionOne
        case optionTwo
        case optionThree

        var id: Option {
            self
        }

        var description: String {
            rawValue.prefix(1).uppercased() + rawValue.dropFirst()
        }
    }

    @Published var selectedOption: Option = .optionOne {
        didSet {
            print("new option selected: \(selectedOption.description)")
        }
    }
}

struct ContentView: View {

    @ObservedObject var viewModel = ViewModel()

    var body: some View {

        NavigationView {
            Form {
                Section(footer: Text("Here is a short description of the setting.")) {
                    Picker(selection: $viewModel.selectedOption,
                           label: Text("Choice")) {
                            Section(footer: Text("This is some additional text to help the user understand the options.")) {
                                ForEach(ViewModel.Option.allCases) { type in
                                    Text(type.description)
                                }
                            }
                    }
                }

            }.navigationBarTitle(Text("Main Screen"))
        }
    }
}

Also, when this list loads I am seeing a weird jump. How can I avoid that?

Sumner answered 21/1, 2020 at 1:7 Comment(0)
I
13

You may not need another dual footer, maybe just a hint title

struct ContentView: View {

    @ObservedObject var viewModel = ViewModel()

    var body: some View {

        NavigationView {
            Form {
                Section(footer: Text("Here is a short description of the setting.")) {
                    Picker(selection: $viewModel.selectedOption,
                           label: Text("Choice")) {

                            ForEach(ViewModel.Option.allCases) { type in
                                Text(type.description)
                            }.navigationBarTitle("hint title here", displayMode: .inline)

                    }
                }.navigationBarTitle("Main Screen", displayMode: .inline)

            }.navigationBarTitle(Text("Main Screen"))
        }
    }
}

Without a picker, you can build your own option lists:

struct ContentView: View {

    @ObservedObject var viewModel = ViewModel()

    var body: some View {

        NavigationView {
            Form {
                Section(footer: Text("Here is a short description of the setting.")) {
                    NavigationLink(destination: SelectionItemView(selection: $viewModel.selectedOption)) {
                        Text("Choice")
                    }


                }.navigationBarTitle("Main Screen", displayMode: .inline)

            }.navigationBarTitle(Text("Main Screen"))
        }
    }
}


struct SelectionItemView: View {

    @Binding var selection: ViewModel.Option
    var body: some View{
        Form{
            Section(footer: Text("Here is a detailed description of the setting.")) {
                ForEach(0 ..< ViewModel.Option.allCases.count, id: \.self) { index in

                    HStack{
                        Button(action: {
                            self.selection  = ViewModel.Option.allCases[index]
                        }){Text(ViewModel.Option.allCases[index].description)}
                        Spacer()
                        if ( self.selection  ==  ViewModel.Option.allCases[index] ){
                            Image(systemName: "checkmark")
                        }
                    }

                }
            }}


    }
}
Intercurrent answered 21/1, 2020 at 4:34 Comment(5)
I'm aware I could change the title, which is already automatically happening based on the Picker's label parameter, but I am specifically wondering how I can add more text under the choices.Sumner
The airdrop one is not a picker. It’s from a navigationlinkIntercurrent
Could you show an example of how to replicate that with NavigationLink?Sumner
Thank you! This is exactly what I needed. To replicate the Picker behavior, I also added the current selection to the right side of the NavigationLink with foregroundColor(.secondary) and changed the foregroundColor of Button to .primarySumner
Thanks to your answer, I solved what seemed like a unrelated problem. Why do you define the title "Main screen" twice? (without that, the picker runs into the problem I linked to above).Koziara

© 2022 - 2024 — McMap. All rights reserved.