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:
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?
Enter SwiftUIHeaderFooterListTutorial as the Product Name, select the Use SwiftUI checkbox, and click Next. Choose a location to save the project on your Mac. In the canvas, click Resume to display the preview. If the canvas isn’t visible, select Editor > Editor and Canvas to show it.
Creating List sections can be achieved by using a Section structure which also allows us to specify custom header and footer views. Finally, use the listStyle modifier to pick default system appearance for the List sections: Questions, comments or suggestions? Follow us on Twitter @theswiftguide
On top of that, we’re going to use a technique which hides empty rows in the List to make it look like this: SwiftUI List with custom section, header and a footer. This look can be achieved by using a ForEach structure which makes a view from an underlying data.
A List can be extended by adding a section with a header or footer. In this tutorial a list of cars is displayed with two different section headers and a footer text. SwiftUI requires Xcode 11 and MacOS Catalina, which the can be download at the Apple developer portal.
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")
}
}
}
}}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With