Как отслеживать масштабирование UIScrollView?
У меня есть масштабирующий UIScrollView и не масштабирующий вид наложения, на котором я анимирую маркеры. Эти маркеры должны отслеживать местоположение некоторого содержимого UIScrollView (аналогично тому, как брошенный pin-код должен отслеживать точку на карте при перемещении и масштабировании).
Я делаю это, вызывая обновление вида наложения в ответ на layoutSubviews
UIScrollView. Это работает, и наложение отлично отслеживается при масштабировании и панорамировании.
Но когда жест щипка заканчивается, UIScrollView автоматически выполняет окончательную анимацию, и вид наложения не синхронизирован на время этой анимации.
Я сделал упрощенный проект, чтобы изолировать эту проблему. UIScrollView содержит оранжевый квадрат, а вид наложения отображает 2-пиксельный красный контур вокруг рамки этого оранжевого квадрата. Как вы можете видеть ниже, красный контур всегда перемещается туда, где он должен быть, за исключением короткого промежутка времени после окончания касания, когда он заметно скачет вперед к финалу положение оранжевого квадрата.Полный проект Xcode для этого теста можно ознакомиться здесь: https://github.com/Clafou/ScrollviewZoomTrackTest, но весь код в двух файлах показано ниже:
TrackedScrollView.swift :
class TrackedScrollView: UIScrollView {
@IBOutlet var overlaysView: UIView?
let square: UIView
required init(coder aDecoder: NSCoder) {
square = UIView(frame: CGRect(x: 50, y: 300, width: 300, height: 300))
square.backgroundColor = UIColor.orangeColor()
super.init(coder: aDecoder)
self.addSubview(square)
self.maximumZoomScale = 1
self.minimumZoomScale = 0.5
self.contentSize = CGSize(width: 500, height: 900)
self.delegate = self
}
override func layoutSubviews() {
super.layoutSubviews()
overlaysView?.setNeedsLayout()
}
}
extension TrackedScrollView: UIScrollViewDelegate {
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return square
}
}
Оверлейсв.swift :
class OverlaysView: UIView {
@IBOutlet var trackedScrollView: TrackedScrollView?
let outline: CALayer
required init(coder aDecoder: NSCoder) {
outline = CALayer()
outline.borderColor = UIColor.redColor().CGColor
outline.borderWidth = 2
super.init(coder: aDecoder)
self.layer.addSublayer(outline)
}
override func layoutSubviews() {
super.layoutSubviews()
if let trackedScrollView = self.trackedScrollView {
CATransaction.begin()
CATransaction.setDisableActions(true)
let frame = trackedScrollView.convertRect(trackedScrollView.square.frame, toView: self)
outline.frame = CGRectIntegral(CGRectInset(frame, -3, -3))
CATransaction.commit()
}
}
}
Среди вещей, которые я пытался использовать, были CADisplayLink
и presentationLayer
, и это позволило мне анимировать наложение, но координаты, которые я получил от presentationLayer
, запаздывали немного позади реального UIScrollView, так что это все еще не выглядело правильным. Я думаю, что правильным подходом было бы связать мое обновление оверлея с созданной системой анимацией UIScrollView, но у меня пока не было успеха в этом взломе.
Как я могу обновить этот код, чтобы всегда отслеживать содержимое масштабирования UIScrollView?
1 ответ:
UIScrollView
посылаетscrollViewDidZoom:
своему делегату в его блоке анимации, если он "отскакивает" назад к своему минимальному или максимальному масштабу, когда щипок заканчивается. Обновите рамки ваших наложений вscrollViewDidZoom:
, еслиzoomBouncing
истинно. Если вы используете автоматический вызов макетаlayoutIfNeeded
.
scrollViewDidZoom:
вызывается только один раз во время анимации отскока зума, но корректировка кадров или вызовlayoutIfNeeded
обеспечит анимацию этих изменений вместе с отскоком Зума, тем самым сохраняя их в идеальном состоянии. синхронизация.Демо:
Исправлен пример проекта: https://github.com/mayoff/ScrollviewZoomTrackTest