swift - "Generic parameter could not be inferred"在 SwiftUI UIViewRepresentable

标签 swift generics swiftui

我有以下代码,可以使用 UIKit 的 UIScrollView在我的 SwiftUI 代码中。它可以粘贴到新的 SwiftUI 项目中。

struct LegacyScrollView<Content: View>: UIViewRepresentable {
    enum Action {
        case idle
        case offset(x: CGFloat, y: CGFloat, animated: Bool)
    }

    @Binding var action: Action
    let content: Content

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> UIScrollView {
        let hosting = UIHostingController(rootView: self.content)
        hosting.view.translatesAutoresizingMaskIntoConstraints = false

        let uiScrollView = UIScrollView()
        uiScrollView.addSubview(hosting.view)

        let constraints = [
            hosting.view.leadingAnchor.constraint(equalTo: uiScrollView.leadingAnchor),
            hosting.view.trailingAnchor.constraint(equalTo: uiScrollView.trailingAnchor),
            hosting.view.topAnchor.constraint(equalTo: uiScrollView.contentLayoutGuide.topAnchor),
            hosting.view.bottomAnchor.constraint(equalTo: uiScrollView.contentLayoutGuide.bottomAnchor),
            hosting.view.widthAnchor.constraint(equalTo: uiScrollView.widthAnchor)
        ]
        uiScrollView.addConstraints(constraints)

        return uiScrollView
    }

    func updateUIView(_ uiView: UIScrollView, context: Context) {
        switch self.action {
        case .offset(let x, let y, let animated):
            uiView.setContentOffset(CGPoint(x: x, y: y), animated: animated)
            DispatchQueue.main.async {
                self.action = .idle
            }
        default:
            break
        }
    }

    class Coordinator: NSObject {
        let legacyScrollView: LegacyScrollView

        init(_ legacyScrollView: LegacyScrollView) {
            self.legacyScrollView = legacyScrollView
        }
    }

    init(@ViewBuilder content: () -> Content) {
        self._action = Binding.constant(Action.idle)
        self.content = content()
    }

    init(action: Binding<Action>, @ViewBuilder content: () -> Content) {
        self._action = action
        self.content = content()
    }
}

struct ContentView: View {
    @State private var action = LegacyScrollView.Action.idle

    var body: some View {
        VStack(spacing: 0) {
            LegacyScrollView(action: self.$action) {
                ForEach(0 ..< 40) { _ in
                    Text("Hello, World!")
                }
            }
            .padding(20)
            .background(Color.gray)
            Spacer()
            Button("Set offset") {
                self.action = LegacyScrollView.Action.offset(x: 0, y: 200, animated: true)
            }.padding()
        }
    }
}

上面的代码将给出 Generic parameter 'Content' could not be inferredContentView的第一行.我试图将行更改为:
@State private var action = LegacyScrollView<AnyView>.Action.idle

但这会产生另一个错误。当我放置 enum Action 时它起作用外struct LegacyScrollView .但在我看来,这是一个相当不优雅的枚举范围。我该如何解决错误消息?

最佳答案

这是允许使用提供的 ContentView 的可能方法原样。

只需更改...的方向,而不是使整个类型泛型,在这种情况下实际上不需要,只需进行泛型初始化,如下所示。

此外,它实际上清楚地表明 Action是内容独立的,这确实是正确的。

在 Xcode 11.2/iOS 13.2 上测试和工作(在 ContentView 中没有变化)

struct LegacyScrollView: UIViewRepresentable {
    enum Action {
        case idle
        case offset(x: CGFloat, y: CGFloat, animated: Bool)
    }

    @Binding var action: Action
    private let uiScrollView: UIScrollView

    init<Content: View>(content: Content) {
        let hosting = UIHostingController(rootView: content)
        hosting.view.translatesAutoresizingMaskIntoConstraints = false

        uiScrollView = UIScrollView()
        uiScrollView.addSubview(hosting.view)

        let constraints = [
            hosting.view.leadingAnchor.constraint(equalTo: uiScrollView.leadingAnchor),
            hosting.view.trailingAnchor.constraint(equalTo: uiScrollView.trailingAnchor),
            hosting.view.topAnchor.constraint(equalTo: uiScrollView.contentLayoutGuide.topAnchor),
            hosting.view.bottomAnchor.constraint(equalTo: uiScrollView.contentLayoutGuide.bottomAnchor),
            hosting.view.widthAnchor.constraint(equalTo: uiScrollView.widthAnchor)
        ]
        uiScrollView.addConstraints(constraints)

        self._action = Binding.constant(Action.idle)
    }

    init<Content: View>(@ViewBuilder content: () -> Content) {
        self.init(content: content())
    }

    init<Content: View>(action: Binding<Action>, @ViewBuilder content: () -> Content) {
        self.init(content: content())
        self._action = action
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> UIScrollView {
        return uiScrollView
    }

    func updateUIView(_ uiView: UIScrollView, context: Context) {
        switch self.action {
        case .offset(let x, let y, let animated):
            uiView.setContentOffset(CGPoint(x: x, y: y), animated: animated)
            DispatchQueue.main.async {
                self.action = .idle
            }
        default:
            break
        }
    }

    class Coordinator: NSObject {
        let legacyScrollView: LegacyScrollView

        init(_ legacyScrollView: LegacyScrollView) {
            self.legacyScrollView = legacyScrollView
        }
    }

}

关于swift - "Generic parameter could not be inferred"在 SwiftUI UIViewRepresentable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60165059/

相关文章:

ios - 使用 Swift/Storyboard 制作 2 个宽度为 50% 的工具栏/页脚按钮

ios - Swift:获取用户的位置坐标作为纬度和经度?

java - ExecutorService 未经检查的分配

c# - 无法转换类型 : why is it necesssary to cast twice?

swift - SwiftUI 和 RealityKit 预览错误 - 类型 'ARView' 的值没有成员 'raycast'

ios - SwiftUI:用于通用(macOS 和 iOS) View 的 UserInterfaceSizeClass

ios - Spritekit Swift 游戏菜单放大屏幕

swift - 来自 Swift 中字符串的类似 Heredoc 的语法

java - 为什么我会收到此泛型类型的未经检查的转换警告?

ios - SwiftUI 动画/转换覆盖 View 不起作用