I'm trying to create a Settings module using SwiftUI.
I have the following hierarchy
- Settings (struct)
- Section (struct)
- Subsection (struct)
- ButtonRow: Row
- Subsection (struct)
- ButtonRow: Row
- ToggleRow: Row
- Subsection (struct)
- Section (struct)
- Subsection (struct)
- ButtonRow: Row
- Subsection (struct)
- Section (struct)
The Row protocol is implemented as follows:
public protocol Row: Identifiable {
var id: UUID { get }
associatedtype Body = View
var body: Body { get }
}
Each Row implementation needs to implement its own View that will be rendered in Settings
struct ButtonRow: Row {
public var id: UUID = UUID()
public var name: String
init(_ name: String) {
self.name = name
}
public var body: some View {
Text("Teste")
}
}
However, I am having the following error in the section highlighted in the code below:

Does anyone know how I can resolve this?
I tried using AnyView(row.body) but I think it is not the best solution in terms of app performance and when I add a Toggle it is not animated.
Edit
I deleted all row subtypes like ButtonRow, ToggleRow, etc and created a single row struct that implements SwiftUI's View protocol.
I deleted all row subtypes like ButtonRow, ToggleRow, etc. and I created a generic row structure that implements SwiftUI's View protocol and can receive any type of View such as Text, Image, Stack...
public struct Row<Content: View>: View {
var id: UUID = UUID()
let content: Content
init(@ViewBuilder _ content: () -> Content) {
self.content = content()
}
public var body: some View {
content
}
}
I also updated my SettingsSection and SettingsSubsection to accept receiving the generic row
@resultBuilder
public enum SubsectionRowsBuilder {
public static func buildBlock<T: View>(_ components: Row<T>...) -> [Row<T>] {
components.map { $0 }
}
public static func buildBlock<T: View>(_ components: [Row<T>]...) -> [Row<T>] {
components.flatMap { $0 }
}
}
public struct SettingsSubsection<T: View>: Identifiable {
public let id = UUID()
let rows: [Row<T>]
public init(@SubsectionRowsBuilder _ rows: () -> [Row<T>]) {
self.rows = rows()
}
}
@resultBuilder
public enum SectionSubsectionsBuilder {
public static func buildBlock<T: View>(_ components: SettingsSubsection<T>...) -> [SettingsSubsection<T>] {
components.map { $0 }
}
public static func buildBlock<T: View>(_ components: Row<T>...) -> [SettingsSubsection<T>] {
let subsection = SettingsSubsection {
components.map { $0 }
}
return [subsection]
}
}
public struct SettingsSection<T: View>: Identifiable {
public let id = UUID()
let name: String?
let footer: String?
let subsections: [SettingsSubsection<T>]
public init(name: String? = nil, footer: String? = nil, @SectionSubsectionsBuilder _ subsections: () -> [SettingsSubsection<T>]) {
self.name = name
self.footer = footer
self.subsections = subsections()
}
}
However, when implementing Settings as in Preview, for example, I cannot create different types within the row, as in the example below:
error:
#Preview {
@State var isOn: Bool = false
return NavigationStack {
Settings { // <-- Generic parameter 'T' could not be inferred
SettingsSection {
Row {
Text("Row 1")
}
}
SettingsSection {
Row {
Text("Row 2")
}
}
SettingsSection {
Row {
Text("Row 3")
}
}
SettingsSection {
Row {
Text("Row 4")
}
}
SettingsSection(name: "Help Us") {
SettingsSubsection { // <-- Cannot convert value of type 'SettingsSubsection<Button<Text>>' to expected argument type 'SettingsSubsection<Text>'
Row {
Text("Row 5")
}
}
SettingsSubsection {
Row {
Button(action: {}) {
Text("Row 6")
}
}
Row {
Button(action: {}) {
Text("Row 7")
}
}
}
}
}
.navigationTitle("Settings")
}
}
