为什么这个 SwiftUI 按钮扩展初始化程序不起作用?
How come this SwiftUI Button extension initializer doesn't work?
我正在尝试在 Button
上创建一个扩展,以在使用系统映像创建它们时减少样板文件。
extension Button {
init(_ systemName: String, action: @escaping () -> Void) {
self.init {
action()
} label: {
Image(systemName: systemName) // <-- Error
}
}
}
这会导致以下编译器错误:
Cannot convert value of type 'Image' to closure result type 'Label'
查看 Button
的初始化程序,我看到它是这样声明的:
struct Button<Label> : View where Label : View {
init(action: @escaping () -> Void, @ViewBuilder label: () -> Label) { ... }
}
但是类似地指定我的扩展名也不起作用。我哪里错了?
extension Button where Label : View {
你需要指定泛型类型,比如
extension Button where Label == Image { // << here !!
init(_ systemName: String, action: @escaping () -> Void) {
self.init {
action()
} label: {
Image(systemName: systemName) // << No Error !!
}
}
}
测试 Xcode 12.5 / iOS 14.5
注意:有关 Text
标签的系统扩展如何声明的详细信息,请参阅
extension Button where Label == Text {
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension Button where Label == Text {
public init(_ titleKey: LocalizedStringKey, action: @escaping () -> Void)
您的方法有两个紧迫的问题:
- 您需要指定您的
Label
类型为 Image
- 您使用的签名将与
Button
(Button(_ title: StringProtocol, action: () -> Void)
) 的现有构造函数冲突
你可以用你的扩展来解决这两个问题:
extension Button where Label == Image {
init(systemName: String, action: @escaping () -> Void) {
self.init(action: action, label: { Image(systemName: systemName) })
}
}
不过感觉更符合SwiftUI的API做自己的Button
包装器:
struct SystemImageButton: View {
let action: () -> Void
let systemName: String
init(systemName: String,
action: @escaping () -> Void) {
self.action = action
self.systemName = systemName
}
var body: some View {
Button(action: action,
label: { Image(systemName: systemName) })
}
}
我正在尝试在 Button
上创建一个扩展,以在使用系统映像创建它们时减少样板文件。
extension Button {
init(_ systemName: String, action: @escaping () -> Void) {
self.init {
action()
} label: {
Image(systemName: systemName) // <-- Error
}
}
}
这会导致以下编译器错误:
Cannot convert value of type 'Image' to closure result type 'Label'
查看 Button
的初始化程序,我看到它是这样声明的:
struct Button<Label> : View where Label : View {
init(action: @escaping () -> Void, @ViewBuilder label: () -> Label) { ... }
}
但是类似地指定我的扩展名也不起作用。我哪里错了?
extension Button where Label : View {
你需要指定泛型类型,比如
extension Button where Label == Image { // << here !!
init(_ systemName: String, action: @escaping () -> Void) {
self.init {
action()
} label: {
Image(systemName: systemName) // << No Error !!
}
}
}
测试 Xcode 12.5 / iOS 14.5
注意:有关 Text
标签的系统扩展如何声明的详细信息,请参阅
extension Button where Label == Text {
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension Button where Label == Text {
public init(_ titleKey: LocalizedStringKey, action: @escaping () -> Void)
您的方法有两个紧迫的问题:
- 您需要指定您的
Label
类型为Image
- 您使用的签名将与
Button
(Button(_ title: StringProtocol, action: () -> Void)
) 的现有构造函数冲突
你可以用你的扩展来解决这两个问题:
extension Button where Label == Image {
init(systemName: String, action: @escaping () -> Void) {
self.init(action: action, label: { Image(systemName: systemName) })
}
}
不过感觉更符合SwiftUI的API做自己的Button
包装器:
struct SystemImageButton: View {
let action: () -> Void
let systemName: String
init(systemName: String,
action: @escaping () -> Void) {
self.action = action
self.systemName = systemName
}
var body: some View {
Button(action: action,
label: { Image(systemName: systemName) })
}
}