Is it possible to make SwiftUI ListMenu with different behaviors?
Inheritance makes it easy to share properties with similar items and then routing Views depending on the type
import SwiftUI
class MenuOption: ObservableObject, Identifiable{
var id: UUID = UUID()
@Published var title: String
init(title: String){
self.title = title
}
}
class MOToggle: MenuOption{
@Published var value: Bool
init(title: String, value: Bool = false){
self.value = value
super.init(title: title)
}
}
class MOOptions: MenuOption{
@Published var selection: Options
enum Options: String, CaseIterable{
case first
case second
case third
case unknown
}
init(title: String, selection: Options = .unknown){
self.selection = selection
super.init(title: title)
}
}
//You can have Views that use each type
struct MenuOptionToggleView: View {
@ObservedObject var option: MOToggle
var body: some View {
Toggle(isOn: $option.value, label: {
Text(option.title)
})
}
}
struct MenuOptionOptionsView: View {
@ObservedObject var option: MOOptions
var body: some View {
Picker(selection: $option.selection, label:
Text(option.title)
, content: {
ForEach(MOOptions.Options.allCases, id:\.rawValue, content: { item in
Text(item.rawValue).tag(item)
})
}).pickerStyle(MenuPickerStyle())
}
}
//And show them all in one View
struct MenuListView: View {
//When they share a type they can be put in an array together
@State var options: [MenuOption] = [MenuOption(title: "say hello"),MOToggle(title: "toggle the option"), MOOptions(title: "show the menu")]
var body: some View {
List(options, id: \.id){option in
//Then when you have the item determine what type it is
if option is MOToggle{
//When you pass it to its designated View
//You convert it to its specifc type
MenuOptionToggleView(option: option as! MOToggle)
} else if option is MOOptions{
//When you pass it to its designated View
//You convert it to its specifc type
MenuOptionOptionsView(option: option as! MOOptions)
} else{
//And since they are if the same type you can have a catch all
Button(action: {
print(option.title)
}, label: {
Text(option.title)
})
}
}
}
}
struct MenuListView_Previews: PreviewProvider {
static var previews: some View {
MenuListView()
}
}
SwiftUI Generic Array Model
Here's a basic example showing a view that has a generic requirement for the @Binding
array like you have:
enum TrafficSignSectionType: String, Codable, Hashable {
case A = "A"
case B = "B"
}
struct TrafficSign: Codable, Hashable, Question { //<-- Here
var id: Int?
var image: String?
var sections: [TrafficSignSectionType.RawValue : String]?
var correct: String?
}
enum PoliceSignSectionType: String, Codable, Hashable {
case A = "A"
case B = "B"
case C = "C"
}
struct PoliceSign: Codable, Hashable, Question { //<-- Here
var id: Int?
var image: String?
var sections: [PoliceSignSectionType.RawValue : String]?
var correct: String?
}
protocol Question : Identifiable { //<-- Here
var image: String? { get set }
}
struct ContentView : View {
@State private var questions : [PoliceSign] = []
@State private var questions2 : [TrafficSign] = []
var body: some View {
QuestionCardView(questions: $questions)
QuestionCardView(questions: $questions2)
}
}
struct QuestionCardView<T: Question>: View {
@Binding var questions: [T]
var body: some View {
ForEach(questions) { question in
Text(question.image ?? "")
}
}
}
You'll want a protocol
that defines the requirements for the type. In your original code, it looked like image
was the only obvious property.
Your original code will have:
struct QuestionCardView<T: Question>: View {
@EnvironmentObject var optionConfigure: OptionConfigure
@Binding var questions: [Question]
How to get the index of the element in the List in SwiftUI when the List is populated with the array?
This can be done using using .enumerated
. For your MenuItem
values it will be as follows
List {
ForEach(Array(menuItems.enumerated()), id: \.1.id) { (index, textItem) in
// do with `index` anything needed here
Text(textItem.text)
}
}
Is it possible to make SwiftUIPager scroll the icons with the newest version?
Option 1
Try changing your implementation of func pageView(_ page: Int) -> some View
:
The idea is to replace the button
items in the pageView
with Image
// MARK: - Page class for Scroll View - Levels icons
func pageView(_ page: Int) -> some View {
Image(uiImage: UIImage(named: LobbyView.levels[page] )!)
.renderingMode(.original)
.resizable()
.aspectRatio(contentMode: .fit)
.onTapGesture {
withAnimation{
// the same action button does
}
}
}
Option 2
If not, go to line 169 inside Pager.swift
(Pod framework):
and swap
wrappedView = AnyView(wrappedView.gesture(allowsDragging ? swipeGesture : nil))
with
wrappedView = AnyView(wrappedView.highPriorityGesture(allowsDragging ? swipeGesture : nil))
I'd go for option 1. Notice in option 2 if you do this, any gesture
you add inside your page content won't be recognized.Fernando Moya de Rivas
SwiftUI: How to remove caret right in NavigationLink which is inside a List
you can do it like this:
var body: some View {
NavigationView() {
List(menu, id: \.self) { section in
VStack{
Text(section.name)
NavigationLink(destination: Dest()) {
EmptyView()
}
}
}
}
Related Topics
Swift Utf8 Encoding and Non Utf8 Character
Swift 2 to 3 Migration Dispatch_Get_Global_Queue
How to Convert Uint16 to Uint8 in Swift 3
Load Desktop Version Wkwebview iOS 9
Naming Convention for Optional Binding
Cannot Add Alamofire to Swift Project
Swiftui Coordinator Not Updating the Containing View's Property
Launch Sudo Command from MACos App Swift
Converting Swift 2.3 to Swift 3.0 - Error, Cannot Invoke 'Datatask' with an Argument List of Type'
Swift: How to Get Form Values Using Eureka Form Builder
My Uiviewcontroller Is Not Filling the Entire Screen
How to Access Firebase Variable Outside Firebase Function
Fblpromises Framework Not Found
Pickers Are Overlapping in iOS 15 Preventing Some of Them to Be Scrolled
How to Mimic 'Uitableviewcontroller' Showing of the Large Titles in 'Navigationbar' on iOS 11
Swift - Reorder Uitableview Cells