找不到宏“Preview(_:body:)”的外部宏实现类型“PreviewsMacros.SwiftUIView”#Preview

external macro implementation type 'PreviewsMacros.SwiftUIView' could not be found for macro 'Preview(_:body:)' #Preview

提问人:Andrew Mead 提问时间:10/23/2023 最后编辑:Ken WhiteAndrew Mead 更新时间:10/23/2023 访问量:265

问:

我正在使用 macOS Ventura 和 Xcode 15.0.1。我已经联系了原始开发人员,但他没有遇到与我相同的错误。该代码应该创建一个按钮。我当然尝试过谷歌搜索,但无济于事。我对新的 Swift 宏知之甚少,所以我对问题可能是什么有点迷茫。我还应该说我对 SwiftUI 相当陌生,但我每天都在学习。

当我运行代码时,出现以下错误:

错误:MyPlayground.playground:191:1:错误:找不到宏“Preview(_:body:)”的外部宏实现类型“PreviewsMacros.SwiftUIView” #Preview {

import Foundation
import SwiftUI

// MARK: - Custom Button Style

struct MobileMeButtonStyle: ButtonStyle {
   // MARK: Metrics
   @ScaledMetric private var cornerRadius = 12
   @ScaledMetric private var horizontalLabelPadding = 12
   @ScaledMetric private var verticalLabelPadding = 8
   @ScaledMetric private var shadowRadius = 2
   @ScaledMetric private var shadowVerticalOffset = 1

   // MARK: Immutable Properties
   private let strokeLineWidth = 1.0

   func makeBody(configuration: Configuration) -> some View {
      configuration.label
         .labelStyle(.mobileMe)
         .padding(.horizontal, horizontalLabelPadding)
         .padding(.vertical, verticalLabelPadding)
         .background(
            RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
               .foregroundStyle(
                  LinearGradient(
                     colors: [
                        Color(red: 58/255, green: 63/255, blue: 66/255),
                        Color(red: 58/255, green: 63/255, blue: 66/255),
                        Color(red: 73/255, green: 76/255, blue: 80/255)
                     ],
                     startPoint: .top,
                     endPoint: .bottom
                  )
               )
               .overlay(
                  // Top reflection
                  ReflectionContainer {
                     UnevenRoundedRectangle(
                        cornerRadii: .init(
                           topLeading: cornerRadius,
                           bottomLeading: (cornerRadius * 0.43).rounded(.down),
                           bottomTrailing: (cornerRadius * 0.43).rounded(.down),
                           topTrailing: cornerRadius
                        ),
                        style: .continuous
                     )
                     .foregroundStyle(
                        LinearGradient(
                           colors: [
                              Color.white,
                              Color.white.opacity(0.24)
                           ],
                           startPoint: .top,
                           endPoint: .bottom
                        )
                     )
                     .blendMode(.plusLighter)
                     .opacity(0.24)
                  }
               )
               .overlay(
                  // Inner light stroke
                  RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
                     .strokeBorder(
                        LinearGradient(
                           colors: [
                              Color.white,
                              Color.white.opacity(0.2),
                              Color.white.opacity(0.24)
                           ],
                           startPoint: .top,
                           endPoint: .bottom
                        ),
                        lineWidth: strokeLineWidth
                     )
                     .blendMode(.plusLighter)
                     .opacity(0.3)
               )
               .overlay(
                  // Outer shadow stroke
                  RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
                     .inset(by: -strokeLineWidth)
                     .strokeBorder(
                        LinearGradient(
                           colors: [
                              Color.black.opacity(0.8),
                              Color.black
                           ],
                           startPoint: .top,
                           endPoint: .bottom
                        ),
                        lineWidth: strokeLineWidth
                     )
                     .opacity(0.34)
               )
         )
         .shadow(
            color: .black.opacity(0.2),
            radius: shadowRadius,
            x: 0,
            y: shadowVerticalOffset
         )
         .padding(.leading, 2)
         .environment(\.buttonRole, configuration.role)
   }
}

// MARK: - Custom Layout

private struct ReflectionContainer: Layout {
   func sizeThatFits(
      proposal: ProposedViewSize,
      subviews: Subviews,
      cache: inout ()
   ) -> CGSize {
      let safeProposal = proposal.replacingUnspecifiedDimensions()
      return CGSize(width: safeProposal.width, height: safeProposal.height)
   }

   func placeSubviews(
      in bounds: CGRect,
      proposal: ProposedViewSize,
      subviews: Subviews,
      cache: inout ()
   ) {
      subviews.first!.place(
         at: CGPoint(x: bounds.minX, y: bounds.minY),
         proposal: .init(
            width: proposal.width ?? 0,
            height: (proposal.height ?? 0) / 1.85
         )
      )
   }
}

// MARK: - Custom Label Style

private struct MobileMeLabelStyle: LabelStyle {
   // MARK: Environment
   @Environment(\.buttonRole) private var role

   // MARK: Metrics
   @ScaledMetric private var shadowRadius = 2
   @ScaledMetric private var shadowVerticalOffset = 1

   func makeBody(configuration: Configuration) -> some View {
      HStack {
         configuration.icon
         configuration.title
      }
      .font(.callout.weight(.medium))
      .foregroundStyle(
         role == .destructive
         ? AnyShapeStyle(Color.red.gradient)
         : AnyShapeStyle(Color.white.gradient.opacity(0.9))
      )
      .shadow(
         color: .black.opacity(role == .destructive ? 0.3 : 0.6),
         radius: shadowRadius,
         x: 0,
         y: shadowVerticalOffset
      )
   }
}

// MARK: - Quality Of Life

extension ButtonStyle where Self == MobileMeButtonStyle {
   static var mobileMe: Self { MobileMeButtonStyle() }
}

extension LabelStyle where Self == MobileMeLabelStyle {
   static var mobileMe: Self { MobileMeLabelStyle() }
}

// MARK: - Environment Extensions

private enum ButtonRoleEnvironmentKey: EnvironmentKey {
   static let defaultValue: ButtonRole? = nil
}

extension EnvironmentValues {
   var buttonRole: ButtonRole? {
      get { self[ButtonRoleEnvironmentKey.self] }
      set { self[ButtonRoleEnvironmentKey.self] = newValue }
   }
}

// MARK: - Preview

#Preview {
   HStack {
      Button(action: {}) {
         Label(
            title: { Text("Today") },
            icon: { EmptyView() }
         )
      }
      Button(role: .destructive, action: {}) {
         Label(
            title: { EmptyView() },
            icon: { Image(systemName: "trash.fill") }
         )
      }
   }
   .padding(.horizontal, 16)
   .padding(.vertical, 16)
   .background(
      RoundedRectangle(cornerRadius: 30, style: .continuous)
         .foregroundStyle(
            LinearGradient(
               colors: [
                  Color(red: 72/255, green: 77/255, blue: 81/255),
                  Color(red: 46/255, green: 48/255, blue: 54/255)
               ],
               startPoint: .top,
               endPoint: .bottom
            )
         )
   )
   .buttonStyle(.mobileMe)
}
swiftui swift-宏

评论


答:

0赞 Sweeper 10/23/2023 #1

您似乎正在使用 Xcode Playground。Xcode Playgrounds 不支持 SwiftUI 预览。(另见)

Xcode Playgrounds 具有实时视图,还允许您“预览”SwiftUI 视图。这与 SwiftUI 预览略有不同,例如,您不能选择不同的设备 - 视图只是“在真空中”显示。

您可以创建一个新的 Xcode 项目,并将代码粘贴到其中,而不是使用 Xcode Playgrounds。如果“画布”没有自动出现,请打开它:

enter image description here

或者,如果您确实想在 Xcode Playground 中预览它,并更改import PlaygroundSupport

#Preview {
    ...
}

PlaygroundPage.current.setLiveView(
    ...
)

手动打开实时取景(如果尚未打开)。它看起来像这样:

enter image description here


请注意,有一个名为 Swift Playgrounds 的类似名称的 app,它确实支持 SwiftUI 预览

评论

0赞 Andrew Mead 10/23/2023
嗨,@Sweeper,感谢您这么快回复。我在一个项目中尝试了它,得到了不同的消息。不确定这是否是进步,哈哈。== 预览更新错误:SchemeBuildError:无法构建方案“button2”链接器命令失败,退出代码为 1(使用 -v 查看调用) 链接按钮 2 (arm64):ld:未定义的符号:_main,引用自:<initial-undefines> clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
0赞 Sweeper 10/23/2023
@AndrewMead 这似乎真的像是 Xcode 的错误。我不知道什么会导致这个错误。尝试使用旧的 PreviewProvider API。如果这也不起作用,我只能说,尝试重新安装 Xcode。
0赞 Andrew Mead 10/23/2023
嗨,@Sweeper,我通过删除导入 Foundation 调用来让它工作。不知道为什么这会让它起作用,但在这一点上我没有抱怨。再次感谢您的帮助