Ответ
Да, реализовывал. Механизм встроенного зума в 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 и новее).
Ответ 18+ 🔞
А, ну ты про встроенный зум в 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. Крутим настройки скролла
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, иначе скроллиться будет в пустоту, волнение ебать.- Конфликты жестов: Если внутри этого скролла ещё кнопки или коллекции сидят, они могут начать драться за тапы. Тут надо через
gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)разбираться, хитрая жопа. contentInsetAdjustmentBehavior: Важная хуйня для айфонов с чёлкой, чтобы контент не уползал под эту ёбаную «монобровь». Без него можно и не заметить, как половина картинки нахуй слетела.