如何跟踪缩放的 UIScrollView?

Cla*_*fou 5 zooming uiscrollview caanimation ios swift

我有一个缩放 UIScrollView 和一个非缩放叠加视图,我可以在其上对标记进行动画处理。这些标记需要跟踪 UIScrollView 某些内容的位置(类似于平移和缩放时放置的图钉需要跟踪地图上的点的方式)。

我通过触发覆盖视图的更新来响应 UIScrollView 的layoutSubviews. 这很有效,并且在缩放和平移时叠加层可以完美跟踪。

但是,当捏合手势结束时,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
    }
}
Run Code Online (Sandbox Code Playgroud)

OverlaysView.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()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试的方法之一是使用CADisplayLinkand presentationLayer,这允许我为叠加层设置动画,但是我获得的坐标presentationLayer稍微落后于实际的 UIScrollView,所以这看起来仍然不正确。我认为正确的方法是将我的覆盖更新与系统创建的 UIScrollView 动画联系起来,但到目前为止我还没有成功破解这个问题。

如何更新此代码以始终跟踪 UIScrollView 的缩放内容?

rob*_*off 6

UIScrollViewscrollViewDidZoom:如果在捏合结束时 \xe2\x80\x9cbouncing\xe2\x80\x9d 返回到其最小或最大缩放,则发送到其动画块中的委托。scrollViewDidZoom:如果为 true ,则更新叠加层的框架zoomBouncing。如果您使用自动布局调用layoutIfNeeded.

\n\n

scrollViewDidZoom:仅在缩放弹跳动画期间调用一次layoutIfNeeded,但调整帧或调用将确保这些更改与缩放弹跳一起进行动画处理,从而使它们保持完美同步。

\n\n

演示:

\n\n

正确动画演示

\n\n

修复示例项目: https: //github.com/mayoff/ScrollviewZoomTrackTest

\n