Как отслеживать масштабирование 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 3

1 ответ:

UIScrollView посылает scrollViewDidZoom: своему делегату в его блоке анимации, если он "отскакивает" назад к своему минимальному или максимальному масштабу, когда щипок заканчивается. Обновите рамки ваших наложений в scrollViewDidZoom:, если zoomBouncing истинно. Если вы используете автоматический вызов макета layoutIfNeeded.

scrollViewDidZoom: вызывается только один раз во время анимации отскока зума, но корректировка кадров или вызов layoutIfNeeded обеспечит анимацию этих изменений вместе с отскоком Зума, тем самым сохраняя их в идеальном состоянии. синхронизация.

Демо:

демонстрация правильной анимации

Исправлен пример проекта: https://github.com/mayoff/ScrollviewZoomTrackTest