I use UIRepresentable to integrate UIScrollView with SwiftUI, and it works fine on display. And I use @ViewBuilder to allow people insert their custom content into my custom scroll view, however I found that @State variable not works in their custom content in my custom scroll view. I am very confused with this problem. Anyone can help me?
I found updateUIView be called when scroll, but I don't know why Text in the @ViewBuilder does not update, and how to make it update.
Demo Project:
import SwiftUI
struct ContentView: View {
@State var speed: CGFloat = 0
@State var offset: CGFloat = 0
var body: some View {
VStack {
// This Text works
Text("Speed: \(speed), Offset: \(offset)")
UIScrollViewControl(speed: $speed, offset: $offset, contentWidth: UIScreen.main.bounds.width, contentHeight: UIScreen.main.bounds.height) {
// This Text never updates
Text("Speed: \(speed), Offset: \(offset)")
}
}
}
}
UIScrollViewControl.swift
struct UIScrollViewControl<Content: View>: UIViewRepresentable {
@Binding var speed: CGFloat
@Binding var offset: CGFloat
var contentHeight: CGFloat
var contentWidth: CGFloat
let content: Content
init(speed: Binding<CGFloat>, offset: Binding<CGFloat>, contentWidth: CGFloat, contentHeight: CGFloat, @ViewBuilder content: () -> Content) {
self._speed = speed
self._offset = offset
self.contentWidth = contentWidth
self.contentHeight = contentHeight
self.content = content()
}
func makeCoordinator() -> Coordinator {
Coordinator(parent1: self)
}
func makeUIView(context: Context) -> UIScrollView {
let view = UIScrollView()
view.contentSize = CGSize(width: 1.0, height: contentHeight)
view.showsHorizontalScrollIndicator = false
view.showsVerticalScrollIndicator = false
view.delegate = context.coordinator
let view1 = UIHostingController(rootView: content)
view1.view.frame = CGRect(x: 0, y: 0, width: contentWidth, height: contentHeight)
view1.view.backgroundColor = .clear
view.addSubview(view1.view)
return view
}
func updateUIView(_ uiView: UIScrollView, context: Context) {
}
class Coordinator: NSObject, UIScrollViewDelegate {
var parent: UIScrollViewControl
init(parent1: UIScrollViewControl) {
parent = parent1
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
parent.speed = 0
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
parent.speed = scrollView.contentOffset.y - parent.offset
parent.offset = scrollView.contentOffset.y
}
}
}