将 UIBarButtonItem 数组转换为 ToolbarItem 数组

问题描述 投票:0回答:1

我是 swiftUI 新手。我们的项目中有 UIKit 和 swiftUI 代码,并且有一些自定义逻辑来添加一些 UIBarButtonItem。我需要将 viewController.navigationItem.rightBarButtonItems 数组从 UIKit 代码传递到单独的 swiftUI 模块,然后使用这些 rightBarButtonItems 创建工具栏。

struct ToolBarItems: ToolbarContent {

    let barButtons: [UIBarButtonItem]
    init(barButtons: [UIBarButtonItem]) {
        self.barButtons = barButtons
    }
    
    var body: some ToolbarContent {
        ToolbarItem(placement: .principal) {
            Text("principal Title")
        }
    }
    
    @ToolbarContentBuilder
    var toolbarButtons: some ToolbarContent {
        ForEach(barButtons) { item in
            ToolbarItem(placement: .navigationBarTrailing) {
                Button(item.title!) {
                    
                }
            }
        }
    }
}

这会给出错误“对静态方法‘buildExpression’的引用没有精确匹配”。不确定如何进行此转换。 请指教。

swiftui toolbar
1个回答
0
投票

错误是因为

ForEach
不是
ToolbarContent
。您可以创建一个
ToolbarItemGroup
,它需要一个
@ViewBuilder
,并且您可以将
ForEach
放在
@ViewBuilder
中:

var body: some ToolbarContent {
    ToolbarItemGroup(placement: .topBarTrailing) {
        ForEach(barButtons) { item in
            Button(item.title!) { ... }
        }
    }
}

此外,您需要

extension UIBarButtonItem: Identifiable {}
才能使
ForEach
正常工作。

然而,

item.title
是主要演员孤立的,但
ToolbarContent.body
不是。虽然您可以将
ToolbarContent.body
隔离到
@MainActor
,但您最终会使用参与者隔离的属性来实现非隔离协议要求,这可能不安全。

我会创建自己的结构来表示“导航栏项目”。例如,如果您只对

UIBarButtonItem
的标题、图像和操作感兴趣,我会创建一个如下结构:

struct NavBarButton: Identifiable {
    let id: ObjectIdentifier
    let title: LocalizedStringKey?
    let image: UIImage?
    let action: () -> Void
    
    @MainActor
    init(_ barButtonItem: UIBarButtonItem) {
        id = ObjectIdentifier(barButtonItem)
        title = barButtonItem.title.map(LocalizedStringKey.init(_:))
        image = barButtonItem.image
        self.action = {
            guard let selector = barButtonItem.action else {
                return
            }
            UIApplication.shared.sendAction(selector, to: barButtonItem.target, from: nil, for: nil)
        }
    }
}

您可以在自定义

ToolbarContent
中使用它,如下所示:

let barButtons: [NavBarButton]

var body: some ToolbarContent {
    ToolbarItemGroup(placement: .topBarTrailing) {
        ForEach(barButtons) { item in
            Button {
                item.action()
            } label: {
                if let title = item.title {
                    Text(title)
                }
                if let image = item.image {
                    Image(uiImage: image)
                }
            }
        }
    }
}

body
View
中,您可以执行以下操作:

.toolbar {
    ToolBarItems(barButtons: uiBarButtonItems.map(NavBarButton.init))
}

NavBarButton.init
是主要演员隔离的,但
View.body
也是如此,所以这没关系。

© www.soinside.com 2019 - 2024. All rights reserved.