Реализовывали ли вы механизм масштабирования (zoom) для содержимого UIScrollView?

«Реализовывали ли вы механизм масштабирования (zoom) для содержимого UIScrollView?» — вопрос из категории UIKit, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, реализовывал. Механизм встроенного зума в UIScrollView требует правильной настройки делегата и вью для масштабирования.

Базовая реализация:

class ZoomableImageView: UIScrollView, UIScrollViewDelegate {
    let imageView = UIImageView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    private func setup() {
        // 1. Добавляем вью для масштабирования
        imageView.contentMode = .scaleAspectFit
        addSubview(imageView)

        // 2. Настраиваем scrollView
        minimumZoomScale = 1.0
        maximumZoomScale = 4.0
        delegate = self
        showsHorizontalScrollIndicator = false
        showsVerticalScrollIndicator = false

        // 3. Добавляем жесты (опционально)
        let doubleTap = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
        doubleTap.numberOfTapsRequired = 2
        addGestureRecognizer(doubleTap)
    }

    // 4. Обязательный метод делегата
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }

    // 5. Обработка двойного тапа для зума
    @objc func handleDoubleTap(_ recognizer: UITapGestureRecognizer) {
        if zoomScale > minimumZoomScale {
            setZoomScale(minimumZoomScale, animated: true)
        } else {
            let tapPoint = recognizer.location(in: imageView)
            let zoomRect = CGRect(x: tapPoint.x, y: tapPoint.y, width: 1, height: 1)
            zoom(to: zoomRect, animated: true)
        }
    }
}

Ключевые моменты:

  • viewForZooming(in:): Должен возвращать единственную вью, которую нужно масштабировать.
  • contentSize: Обычно выставляется равным размеру содержимого (например, imageView.frame.size).
  • Конфликты жестов: Если внутри UIScrollView есть другие интерактивные элементы (кнопки, коллекции), может потребоваться обработка через gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:).
  • contentInsetAdjustmentBehavior: Важно для корректного отображения на устройствах с "чёлкой" (iPhone X и новее).