No exact matches in reference to static method 'buildExpression'

50 views Asked by At

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
    • Section (struct)
      • Subsection (struct)
        • ButtonRow: Row

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:

enter image description here

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")
    }
}

The result should be like the image below: enter image description here

0

There are 0 answers