“无法推断出通用参数".在SwiftUI UIViewRepresentable中 [英] "Generic parameter could not be inferred" in SwiftUI UIViewRepresentable
问题描述
我有以下代码,这使得在我的SwiftUI代码中使用UIKit的UIScrollView
成为可能.可以将其粘贴到新的SwiftUI项目中.
I've got the following code, which makes it possible to use the UIKit's UIScrollView
in my SwiftUI code. It can be pasted in a new SwiftUI project.
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()
}
}
}
上面的代码将在ContentView
的第一行给出Generic parameter 'Content' could not be inferred
.我尝试将行更改为:
The code above will give Generic parameter 'Content' could not be inferred
on the first line of the ContentView
. I've tried to change the line to:
@State private var action = LegacyScrollView<AnyView>.Action.idle
但是这会带来另一个错误.当我将enum Action
放在struct LegacyScrollView
之外时,它可以工作.但是我认为,这是对该枚举的相当小范围的界定.我该如何解决错误消息?
but that will give another error. It works when I place the enum Action
outside the struct LegacyScrollView
. But in my opinion, that's a rather inelegant scoping of this enum. How can I solve the error message?
推荐答案
以下是允许按原样使用提供的ContentView
的方法.
Here is possible approach that allows usage of provided ContentView
as-is.
只需更改...的方向,而不是使整个类型通用(在这种情况下实际上并不需要),只需对通用类型进行初始化,如下所示.
Just change the direction of... instead of making entire type generic, which is actually not needed in this case, just make a generic only initialisation, like below.
实际上,这也清楚地表明Action
是与内容无关的,这确实是正确的.
Also it actually makes clear that Action
is Content-independent, that is really correct.
经过测试的适用于Xcode 11.2/iOS 13.2(在ContentView
中没有任何更改)
Tested & works with Xcode 11.2 / iOS 13.2 (w/o no changes in 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
}
}
}
这篇关于“无法推断出通用参数".在SwiftUI UIViewRepresentable中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!