我是 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’的引用没有精确匹配”。不确定如何进行此转换。 请指教。
错误是因为
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
也是如此,所以这没关系。