Date Archives

September 2019

Adaptive Image Viewer using UIScrollView

Having an image viewer within your app is a trivial feature; For one of my apps I needed one and found a tutorial on Ray Wenderlich website but it was not exactly what I wanted. You could zoom in and out the image but the image sticked to the top left corner of the screen, I wanted it to be centered. Also, is not it nicer for this simple UI to do everything in code? no dealing with storyboard for constraints and two elements makes maintaining the code easer in the future.

let scrollView = UIScrollView() let imageView: UIImageView = { let _imageView = UIImageView() _imageView.translatesAutoresizingMaskIntoConstraints = false return _imageView }() override func viewDidLoad() { super.viewDidLoad() setupScrollView() setupViews() } override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() if let image = UIImage(named: "image.jpg") { scrollView.contentSize = image.size imageView.image = image let minZoom = min(self.view.bounds.size.width / image.size.width, self.view.bounds.size.height / image.size.height) self.scrollView.minimumZoomScale = minZoom DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { let vertical = (self.view.bounds.size.height - (image.size.height * minZoom)) / 2 self.scrollView.contentInset = UIEdgeInsets(top: vertical, left: 0, bottom: vertical, right: 0) self.scrollView.setZoomScale(minZoom, animated: true) } } } func setupScrollView(){ scrollView.translatesAutoresizingMaskIntoConstraints = false imageView.translatesAutoresizingMaskIntoConstraints = false scrollView.delegate = self view.addSubview(scrollView) scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true scrollView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true scrollView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true scrollView.minimumZoomScale = 0.2 } func setupViews(){ scrollView.addSubview(imageView) } func centerContent() { var top: CGFloat = 0 var left: CGFloat = 0 if scrollView.contentSize.width < scrollView.bounds.size.width { left = (scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 } if scrollView.contentSize.height < scrollView.bounds.size.height { top = (scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 } scrollView.contentInset = UIEdgeInsets(top: top, left: left, bottom: top, right: left) }

The last step is conforming to UIScrollViewDelegate protocol:

func viewForZooming(in scrollView: UIScrollView) -> UIView? { return imageView } func scrollViewDidZoom(_ scrollView: UIScrollView) { centerContent() }

You can download the project from github.