UIViewRepresentable 不更新 swiftui 中的发布/绑定属性
UIViewRepresentable not updating Published / Binding properties in swiftui
我正在尝试将 UIScrollView 包装在 SwiftUI 中以获得一些额外的功能。我想访问 UIScrollView 的 contentOffset 属性 并将其分配给某些 属性(已发布
或绑定)在 SwiftUI 中,但 SwiftUI(我的 ContentView)未检测到任何 属性 更改。你能帮我把它弄好吗?
这是我的 UIScrollView
import SwiftUI
import UIKit
struct MyScrollView<Content: View>: UIViewRepresentable {
@ObservedObject var viewModel: ViewModel
@ViewBuilder var content: () -> Content
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIScrollViewDelegate {
var parent: MyScrollView
init(_ parent: MyScrollView) {
self.parent = parent
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
parent.viewModel.scrollviewContentOffset = scrollView.contentOffset.y
}
}
func makeUIView(context: Context) -> UIScrollView {
let scrollView = UIScrollView()
scrollView.delegate = context.coordinator
scrollView.isScrollEnabled = true
let child = UIHostingController(rootView: content())
scrollView.addSubview(child.view)
let newSize = child.view.sizeThatFits(CGSize(width: UIScreen.screenWidth, height: UIScreen.screenHeight))
child.view.frame = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
scrollView.contentSize = newSize
return scrollView
}
func updateUIView(_ uiView: UIScrollView, context: Context) {
//
}
typealias UIViewType = UIScrollView
}
这是我的 ContentView
import SwiftUI
class ViewModel: ObservableObject {
@Published var scrollviewContentOffset = CGFloat.zero
}
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
MyScrollView(viewModel: viewModel) {
ForEach(0..<100) { i in
Text("\(i)")
.offset(y: viewModel.scrollviewContentOffset / CGFloat(i + 1)
}
}
}
}
您仅在创建 MyScrollView
时捕获初始 content
,而不是在视图模型更改时更新它。
您需要在 updateUIView
内设置更新 content
。例如,您可以将 hostingController
存储在 Coordinator
:
中
struct MyScrollView<Content: View>: UIViewRepresentable {
@StateObject var viewModel: ViewModel
@ViewBuilder var content: () -> Content
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIScrollViewDelegate {
let parent: MyScrollView
var hostingController: UIHostingController<Content>!
init(_ parent: MyScrollView) {
self.parent = parent
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
parent.viewModel.scrollviewContentOffset = scrollView.contentOffset.y
}
}
func makeUIView(context: Context) -> UIScrollView {
let scrollView = UIScrollView()
scrollView.delegate = context.coordinator
scrollView.isScrollEnabled = true
let child = UIHostingController(rootView: content())
context.coordinator.hostingController = child
scrollView.addSubview(child.view)
let newSize = child.view.sizeThatFits(CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
child.view.frame = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
scrollView.contentSize = newSize
return scrollView
}
func updateUIView(_ uiView: UIScrollView, context: Context) {
context.coordinator.hostingController.rootView = content()
}
}
我正在尝试将 UIScrollView 包装在 SwiftUI 中以获得一些额外的功能。我想访问 UIScrollView 的 contentOffset 属性 并将其分配给某些 属性(已发布 或绑定)在 SwiftUI 中,但 SwiftUI(我的 ContentView)未检测到任何 属性 更改。你能帮我把它弄好吗?
这是我的 UIScrollView
import SwiftUI
import UIKit
struct MyScrollView<Content: View>: UIViewRepresentable {
@ObservedObject var viewModel: ViewModel
@ViewBuilder var content: () -> Content
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIScrollViewDelegate {
var parent: MyScrollView
init(_ parent: MyScrollView) {
self.parent = parent
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
parent.viewModel.scrollviewContentOffset = scrollView.contentOffset.y
}
}
func makeUIView(context: Context) -> UIScrollView {
let scrollView = UIScrollView()
scrollView.delegate = context.coordinator
scrollView.isScrollEnabled = true
let child = UIHostingController(rootView: content())
scrollView.addSubview(child.view)
let newSize = child.view.sizeThatFits(CGSize(width: UIScreen.screenWidth, height: UIScreen.screenHeight))
child.view.frame = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
scrollView.contentSize = newSize
return scrollView
}
func updateUIView(_ uiView: UIScrollView, context: Context) {
//
}
typealias UIViewType = UIScrollView
}
这是我的 ContentView
import SwiftUI
class ViewModel: ObservableObject {
@Published var scrollviewContentOffset = CGFloat.zero
}
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
MyScrollView(viewModel: viewModel) {
ForEach(0..<100) { i in
Text("\(i)")
.offset(y: viewModel.scrollviewContentOffset / CGFloat(i + 1)
}
}
}
}
您仅在创建 MyScrollView
时捕获初始 content
,而不是在视图模型更改时更新它。
您需要在 updateUIView
内设置更新 content
。例如,您可以将 hostingController
存储在 Coordinator
:
struct MyScrollView<Content: View>: UIViewRepresentable {
@StateObject var viewModel: ViewModel
@ViewBuilder var content: () -> Content
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIScrollViewDelegate {
let parent: MyScrollView
var hostingController: UIHostingController<Content>!
init(_ parent: MyScrollView) {
self.parent = parent
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
parent.viewModel.scrollviewContentOffset = scrollView.contentOffset.y
}
}
func makeUIView(context: Context) -> UIScrollView {
let scrollView = UIScrollView()
scrollView.delegate = context.coordinator
scrollView.isScrollEnabled = true
let child = UIHostingController(rootView: content())
context.coordinator.hostingController = child
scrollView.addSubview(child.view)
let newSize = child.view.sizeThatFits(CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
child.view.frame = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
scrollView.contentSize = newSize
return scrollView
}
func updateUIView(_ uiView: UIScrollView, context: Context) {
context.coordinator.hostingController.rootView = content()
}
}