Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static method 'buildBlock' requires that 'ToolbarItem<Void, Text>' conform to 'View'

Tags:

xcode

swiftui

I'm supporting iOS 13 and up. I wish to use the new .toolbar modifier for an optional feature, in devices using iOS 14 and up. I'm using Xcode 13.0 RC 1, build 13A233, but the issue also occurs in Xcode 12.5.1. I have created the following code:

import SwiftUI

struct MyToolbar<T>: ViewModifier where T: View {
    let toolbarContent: () -> T
    
    func body(content: Content) -> some View {
        if #available(iOS 14.0, *) {
            content
                .toolbar(content: self.toolbarContent)
        }
    }
}

extension View {
    func myToolbar<T: View>(@ViewBuilder content: @escaping () -> T) -> some View {
        self.modifier(MyToolbar(toolbarContent: content))
    }
}

struct MyToolbar_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            Text("Hello, world")
                .myToolbar {
                    if #available(iOS 14.0, *) {
                        Text("Hello, world!")
//                        ToolbarItem(placement: .bottomBar) {
//                            Text("Hello, world!")
//                        }
                    } else {
                        EmptyView()
                    }
                }
        }
    }
}

I have included the preview bit, so the above can be pasted into an empty file in any Xcode SwiftUI project. It works. When I uncomment the ToolbarItem statement, I get the following errors:

Static method 'buildBlock' requires that 'ToolbarItem<Void, Text>' conform to 'View'
Static method 'buildLimitedAvailability' requires that 'ToolbarItem<Void, Text>' conform to 'View'

How can I fix these errors?

like image 243
Bart van Kuik Avatar asked Oct 28 '25 04:10

Bart van Kuik


2 Answers

You can use the @ToolbarContentBuilder

extension View {

    @ToolbarContentBuilder
    func toolbarContent() -> some ToolbarContent {
        ...
    }

You can add your extension like this

func body(content: Content) -> some View {
        if #available(iOS 14.0, *) {
            content
                .toolbar(content: self.toolbarContent)
        }
}
like image 64
Adam Wareing Avatar answered Oct 29 '25 18:10

Adam Wareing


I think the main issue is that the .toolbar modifier's block is defined to return something conforming to the ToolbarContent protocol. From the docs:

func toolbar<Content>(content: () -> Content) -> some View where Content : ToolbarContent

As such, within your view modifier

func body(content: Content) -> some View {
    if #available(iOS 14.0, *) {
        content
            .toolbar(content: self.toolbarContent)
    }
}

… you need to ensure that self.toolbarContent matches that () -> ToolbarContent type signature.

Just from glancing at your code, I'd be inclined to first try changing your conformance of T from T: View to T: ToolbarContent. By eye that looks like it might be enough, but it's possible you might need to do a bit more work to tidy everything up.

like image 33
Scott Matthewman Avatar answered Oct 29 '25 20:10

Scott Matthewman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!