I need to embed an UIScrollView
in a SwiftUI view hierarchy. I wrapped one in UIViewRepresentable
, but for some reason my scroll view has zero width.
How do I make the connection between the outer SwiftUI views and the autolayout constraints that define the size of the UIScrollView
, so that it expands to fill the space given to it by SwiftUI?
In the sample below, I create a simple "content view" to be inside the UIScrollView
. It is is too wide for my screen (500), so will use horizontal scrolling. It simply draws two colored boxes side by side.

struct ContentView: View {
var body: some View {
VStack {
Text("Wrapped UIScrollView Test").padding()
Divider()
WrappedScrollView()
Spacer()
}
}
}
struct WrappedScrollView: UIViewRepresentable {
typealias UIViewType = MyScrollView
func makeUIView(context: Context) -> MyScrollView {
let v = MyScrollView()
return v
}
func updateUIView(_ uiView: MyScrollView, context: Context) {}
}
class MyScrollView: UIScrollView {
init() {
super.init(frame: .zero)
translatesAutoresizingMaskIntoConstraints = false
let content = MyContentView()
self.addSubview(content)
// This is how you define the scrollable area with UIScrollView
content.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
content.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
content.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
content.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
// I only want to scroll horizontally
self.heightAnchor.constraint(equalTo: content.heightAnchor).isActive = true
// But I have to use this hack to get it to show up. (320 is width of my screen)
// self.widthAnchor.constraint(equalToConstant: 320).isActive = true
}
required init?(coder: NSCoder) { fatalError() }
}
// Just two blue and green squares, so you can see scrolling.
class MyContentView: UIView {
init() {
super.init(frame:.zero)
translatesAutoresizingMaskIntoConstraints = false
}
required init?(coder: NSCoder) { fatalError() }
override var intrinsicContentSize: CGSize {
return .init(width: 500, height: 200)
}
override func draw(_ rect: CGRect) {
print("draw \(bounds)")
guard let c = UIGraphicsGetCurrentContext() else { return }
var r1 = bounds
r1.size.width = 250
var r2 = r1
r2.origin.x = 250
c.setFillColor(UIColor.blue.cgColor)
c.fill(r1)
c.setFillColor(UIColor.green.cgColor)
c.fill(r2)
}
}