2014-11-04 90 views
3

我有一個縮放的UIScrollView,和一個非縮放的疊加視圖,我在這個視圖上設置了動畫標記。這些標記需要跟蹤UIScrollView的一些內容的位置(類似於在平移和縮放時丟棄的引腳需要在地圖上追蹤地點的方式)。如何跟蹤縮放UIScrollView?

我通過響應UIScrollView的layoutSubviews觸發重疊視圖的更新操作。這是有效的,並且在縮放和平移時覆蓋層完美地追蹤。

但當捏手勢結束的UIScrollView自動執行最後的動畫,並且該覆蓋圖是不同步的該動畫的持續時間。

我做了一個簡化的項目來隔離這個問題。 UIScrollView包含一個橙色正方形,覆蓋視圖在這個橙色正方形的框架周圍顯示一個2像素的紅色輪廓。正如你在下面看到的那樣,紅色輪廓總是移動到它應該在的位置,除非觸摸結束後的一小段時間,當它明顯跳到橙色方塊的最終位置時。

red line around a zooming rectangle

本次測試的完整的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 
    } 
} 

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() 
     } 
    } 
} 

其中我試過的東西是使用CADisplayLinkpresentationLayer這允許我爲覆蓋層設置動畫,但我從presentationLayer獲得的座標稍微落後於實際的UIScrollView,所以這看起來仍然不正確。我認爲正確的做法是將我的覆蓋更新與系統創建的UIScrollView動畫綁定,但是迄今爲止我還沒有取得成功。

如何更新驗證碼總是跟蹤UIScrollView的縮放內容?

回答

4

UIScrollView在其動畫塊中將scrollViewDidZoom:發送給其委託人,如果它在收縮結束時「彈回」回到其最小或最大縮放比例。如果zoomBouncing爲true,則更新scrollViewDidZoom:中覆蓋圖的幀。如果您使用自動佈局,請致電layoutIfNeeded

scrollViewDidZoom:變焦反彈動畫過程中只調用一次調整您的框架或致電layoutIfNeeded將確保這些變化與變焦反彈沿着動畫,從而保持它們完全同步。

演示:

demo of correct animation

固定樣本項目:https://github.com/mayoff/ScrollviewZoomTrackTest

+0

整潔!我的印象是'scrollViewDidZoom:'只被調用一次,而不是在動畫的每一步。我非常感謝你的幫助。 – Clafou 2014-11-07 13:25:32

+0

順便說一下,我向Apple Developer Technical Support發送了同一個項目和動畫截圖的完全相同的問題,這是他們的迴應:「我們的工程師已審覈您的請求,並確定這最好作爲錯誤報告處理」 。堆棧1:Apple支持0 – Clafou 2014-11-07 13:30:31

+0

最後說明:代理的'scrollViewDidScroll:'也需要類似的實現,因爲在某些情況下,動畫不是縮放而是重新重新調入滾動視圖的平移。並且非常感謝你Rob的真棒回答! – Clafou 2014-11-07 17:21:58