首页 > 解决方案 > SwiftUI - 代码中的扩展定义放置

问题描述

Xcode 最近让我很头疼,因为它使用了一个将 SwiftUI 视图转换为 UIImage 的扩展。该项目主要是 SwiftUI 通用应用程序。我需要用于 ClockKit Complications 定义的 UIImage,并且我发现以下代码理论上应该可以做到这一点:

extension View {
    func snapshot() -> UIImage {
        let controller = UIHostingController(rootView: self)
        let view = controller.view

        let targetSize = controller.view.intrinsicContentSize
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear

        let renderer = UIGraphicsImageRenderer(size: targetSize)

        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
}

问题是:

  1. Xcode 只允许将扩展放在主 ContentView 的顶部,watchOS Extension 不会检测到它(因为它有自己的 ContentView,不能共享或设置为两者的目标成员)。在代码中的任何其他地方,我都会收到以下错误
  2. 即使扩展在主 ContentView 中没有给出错误,那么常量声明也不起作用,它会给出以下错误。如果将其更改为let exportimage: UIImage = MoonView.snapshot(MoonView)它,则只需说Cannot convert value of type 'MoonView.Type' to expected argument type 'MoonView'

如何解决问题?可以放置扩展名的问题吗?Xcode 版本 12.5,我清理了构建文件夹,但找不到任何与名称相似的地方。在所有代码文件中,SwiftUI 和 UIKit 库都被导入(即使后者对于编译器来说似乎并不是最重要的)。

非常感谢所有的贡献。

标签: iosswiftxcodeswiftuiuikit

解决方案


给定以下扩展名:

extension View {
  func sayHello() {
    print("Hello, world!")
  }
}

为了实现#1,您可以将扩展名放在其自己的文件中,然后将其分配给将使用它的每个目标。

然后,正如@aheze 在评论中指出的那样,您必须在 View 的实例(而不是 View 类型本身)上调用该函数。所以:

MoonView().sayHello()

但是,在您的情况下,您看到错误的原因(如Cannot find UIHostingController范围内)是因为WatchOSUIHostingControllerUIGraphicsImageRenderer不可用(请参阅https://developer.apple.com/documentation/swiftui/uihostingcontrollerhttps:// developer.apple.com/documentation/uikit/uigraphicsimagerenderer),这意味着所写的扩展程序不会在该平台上编译。


推荐阅读