I am trying to update my content inside the scroll view but since makeUIView
called only once when view builds. It doesn't refresh when I click on 1 image and then 2 images.
However, If I click on No image and then click on Image 2 it works as expected.
Here is my code.
struct ContentView: View {
@State var images:[String] = []
var body: some View {
VStack{
HStack{
Button(action: { self.images = [] }, label: {
Text("No Images")
})
Button(action: { self.images = ["sample_1"] }, label: {
Text("1 Images")
})
Button(action: { self.images = ["sample_1","sample_2"] }, label: {
Text("2 Images")
})
}
if self.images.count > 0{
GeometryReader { (reader) in
STHorizontalScrollView(images: self.images, size: reader.size)
}
}else{
Text("No Images")
}
}
}
}
struct STHorizontalScrollView:UIViewRepresentable {
var images:[String]
var size:CGSize
func makeUIView(context: Context) -> UIScrollView {
let scrollView = UIScrollView()
// Calculating the Width
let widthForContent = CGFloat(self.images.count) * size.width
scrollView.contentSize = CGSize.init(width: widthForContent, height: size.height)
scrollView.isPagingEnabled = true
// Hosting Controller
let hostingController = UIHostingController(rootView: HorizontalList(images: images, size: size))
hostingController.view.frame = CGRect.init(x: 0, y: 0, width: widthForContent, height: size.height)
// Add View to scrollview
scrollView.addSubview(hostingController.view)
return scrollView
}
func updateUIView(_ uiView: UIScrollView, context: Context) {
}
}
struct HorizontalList:View {
var images:[String]
var size:CGSize
var body: some View{
HStack(spacing: 0.0) {
ForEach(self.images, id:\.self){ image in
Image(image)
.resizable()
.aspectRatio(contentMode: ContentMode.fill)
.frame(width: self.size.width, height: self.size.height)
.clipped()
}
}
}
}
Not sure what to write here in the update method as the actual content is inside HorizontalList
struct.
Any help will be appreciated.
Thanks
Representable is updated whenever some binding of dependent data is updated, so you need to rebuild internals in update updateUIView
when images changes.
Here is a solution. Tested with Xcode 11.4 / iOS 13.4
Usage of representable
// images as binding
STHorizontalScrollView(images: self.$images, size: reader.size)
and representable itself
struct STHorizontalScrollView:UIViewRepresentable {
@Binding var images:[String]
var size:CGSize
func makeUIView(context: Context) -> UIScrollView {
UIScrollView()
}
func updateUIView(_ scrollView: UIScrollView, context: Context) {
_ = scrollView.subviews.map { $0.removeFromSuperview() }
guard images.count != 0 else { return }
// Calculating the Width
let widthForContent = CGFloat(self.images.count) * size.width
scrollView.contentSize = CGSize.init(width: widthForContent, height: size.height)
scrollView.isPagingEnabled = true
// Hosting Controller
let hostingController = UIHostingController(rootView: HorizontalList(images: images, size: size))
hostingController.view.frame = CGRect.init(x: 0, y: 0, width: widthForContent, height: size.height)
// Add View to scrollview
scrollView.addSubview(hostingController.view)
}
}