I'm trying to learn UIKit and toying around with a UIScrollView
. My goal is to create a UIScrollView
that contains an image that I can pan and zoom.
Upon first render, as title says, the image's origin matches the UIScrollView
's (bounds) center. As soon as I double tap to reset zoom, the issue fixes itself.
Issue visualization in simulator
This is my attempt:
import UIKit
import SnapKit
import SMScrollView
open class PinchableImageVC: UIViewController, UIScrollViewDelegate {
private let dataSource: String
private let minimumZoomScale: CGFloat = 1.0
private let maximumZoomScale: CGFloat = 20.0
lazy internal var scrollView: SMScrollView = { [unowned self] in
let scrollView = SMScrollView(frame: .zero)
scrollView.minimumZoomScale = self.minimumZoomScale
scrollView.maximumZoomScale = self.maximumZoomScale
scrollView.zoomScale = 1.0
scrollView.bouncesZoom = true
scrollView.isPagingEnabled = false
scrollView.delegate = self
scrollView.showsHorizontalScrollIndicator = false
scrollView.decelerationRate = UIScrollView.DecelerationRate.fast
scrollView.backgroundColor = .systemMint
scrollView.stickToBounds = true
scrollView.fitOnSizeChange = false
return scrollView
}()
lazy internal var imageView: UIImageView = {
guard let image = UIImage(named: dataSource) else {
fatalError("assets.xcassets doesn't include any image named \'\(dataSource)\'.")
}
let imageView = UIImageView(image: image)
return imageView
}()
internal init(dataSource: String) {
self.dataSource = dataSource
super.init(nibName: nil, bundle: nil)
}
public required init(coder: NSCoder) {
fatalError("Uh uh you're not expected to invoke \(#function)")
}
open override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemRed
view.addSubview(self.scrollView)
scrollView.addSubview(self.imageView)
scrollView.snp.makeConstraints { make in
make.left.top.right.bottom.equalTo(self.view)
}
}
open override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
imageView.frame = scrollView.bounds
}
public func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return self.imageView
}
}
Assuming this is the code you are using: SMScrollView ...
After taking a quick look, adding this to your controller should center the image on launch:
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
scrollView.zoomScale = 1.0
}
You will probably quickly find out that SMScrollView isn't handling scroll view size changes (such as on device rotation)... and, if you want to keep the image aspect ratio and set imageView.contentMode = .scaleAspectFit
, you can pan the image completely out of view.