为什么这个 SwiftUI Button 扩展初始化器不起作用?

zek*_*kel 5 button swiftui

我正在尝试创建一个扩展,以Button减少使用系统映像创建它们时的样板文件。

extension Button {
  init(_ systemName: String, action: @escaping () -> Void) {
    self.init {
      action()
    } label: {
      Image(systemName: systemName) // <-- Error
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这会导致以下编译器错误:

无法将“Image”类型的值转换为闭包结果类型“Label”

查看 的Button初始值设定项,我看到它是这样声明的:

struct Button<Label> : View where Label : View {
  init(action: @escaping () -> Void, @ViewBuilder label: () -> Label) { ... }
}
Run Code Online (Sandbox Code Playgroud)

但类似地指定我的扩展名也不起作用。我哪里出错了?

extension Button where Label : View {

pie*_*bie 4

您的方法有两个直接问题:

  1. 您需要指定您的Label类型Image
  2. 您使用的签名将与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) })
  }
}
Run Code Online (Sandbox Code Playgroud)

但感觉更符合 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) })
  }
}
Run Code Online (Sandbox Code Playgroud)