2017-04-18 26 views
3

要對Snapchat的HUD運動產生類似的效果,我創建了基於UIScollView'scontentOffset的HUD元素的運動。 編輯:Link to the Github project如何在UIScrollView運動中正確轉換UIView的縮放比例

func scrollViewDidScroll(_ scrollView: UIScrollView) { 
    self.view.layoutIfNeeded() 

    let factor = scrollView.contentOffset.y/self.view.frame.height 

    self.transformElements(self.playButton, 
          0.45 + 0.55 * factor, // 0.45 = desired scale + 0.55 = 1.0 == original scale 
          Roots.screenSize.height - 280, // 280 == original Y 
          Roots.screenSize.height - 84, // 84 == minimum desired Y 
          factor) 
} 

func transformElements(_ element: UIView?, 
         _ scale: CGFloat, 
         _ originY: CGFloat, 
         _ desiredY: CGFloat, 
         _ factor: CGFloat) { 
    if let e = element { 
     e.transform = CGAffineTransform(scaleX: scale, y: scale) // this line lagging 

     let resultY = desiredY + (originY - desiredY) * factor 
     var frame = e.frame 
     frame.origin.y = resultY 
     e.frame = frame 
    } 
} 

使用此代碼實現滾動以及過渡似乎是「laggy」/不光滑。 (物理iPhone 6S +和7+)。

刪除以下行:e.transform = CGAffineTransform(scaleX: scale, y: scale)刪除了該問題。滾動以及UIView對象的Y-movement再次平滑。

什麼是最佳的方法來改變一個對象的規模?

enter image description here

有沒有佈局約束。

func setupPlayButton() { 
     let rect = CGRect(x: Roots.screenSize.width/2 - 60, 
          y: Roots.screenSize.height - 280, 
          width: 120, 
          height: 120) 
     self.playButton = UIButton(frame: rect) 
     self.playButton.setImage(UIImage(named: "playBtn")?.withRenderingMode(.alwaysTemplate), for: .normal) 
     self.playButton.tintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) 
     self.view.addSubview(playButton) 
} 
+0

您的按鈕是否有透明背景?如果確實如此,您可以關閉它並重試嗎?你也可以在動畫時嘗試'button.layer.shouldRasterize = true'。 – dmorrow

+0

該按鈕沒有顏色。只是一個UIImage(pdf與透明元素) –

+0

從你的gif,嘗試設置背景黑色。 – dmorrow

回答

1

這是發生,因爲你申請兩個:transformframe。如果您僅應用transform,它將會更順暢。更新您的transformElements功能如下:

func transformElements(_ element: UIView?, 
         _ scale: CGFloat, 
         _ originY: CGFloat, 
         _ desiredY: CGFloat, 
         _ factor: CGFloat) { 
    if let e = element { 
     e.transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: 0, y: desiredY * (1 - factor)) 

    } 
} 
+0

好。該公式不再適用於這種方法。但過渡很順利。只需要調整公式。認爲這將是我的出路。感謝您的幫助 –

1

您可以通過創建一個動畫則該層的速度設置爲0,然後改變層的timeOffset使這些類型的動畫更加平滑的。

先添加動畫在setupPlayButton方法

let animation = CABasicAnimation.init(keyPath: "transform.scale") 
animation.fromValue = 1.0 
animation.toValue = 0.45 
animation.duration = 1.0 
//Set the speed of the layer to 0 so it doesn't animate until we tell it to 
self.playButton.layer.speed = 0.0; 
self.playButton.layer.add(animation, forKey: "transform"); 
scrollViewDidScroll變化的層的下一個timeOffset和

移動的按鈕的中心。

if let btn = self.playButton{ 
    var factor:CGFloat = 1.0 
    if isVertically { 
     factor = scrollView.contentOffset.y/self.view.frame.height 
    } else { 
     factor = scrollView.contentOffset.x/Roots.screenSize.width 
     var transformedFractionalPage: CGFloat = 0 

     if factor > 1 { 
      transformedFractionalPage = 2 - factor 
     } else { 
      transformedFractionalPage = factor 
     } 
     factor = transformedFractionalPage; 
    } 
    //This will change the size 
    let timeOffset = CFTimeInterval(1-factor) 
    btn.layer.timeOffset = timeOffset 

    //now change the positions. only use center - not frame - so you don't mess up the animation. These numbers aren't right I don't know why 
    let desiredY = Roots.screenSize.height - (280-60); 
    let originY = Roots.screenSize.height - (84-60); 
    let resultY = desiredY + (originY - desiredY) * (1-factor) 
    btn.center = CGPoint.init(x: btn.center.x, y: resultY); 
} 

我不能完全得到正確的按鈕的位置 - 這樣的東西是錯誤與我的數學,但我相信你可以解決它。

如果您想了解此技術的更多信息請看這裏:http://ronnqvi.st/controlling-animation-timing/

+0

你的方法正在工作。但另一個答案更容易,接近我的方法。但我會拭目以待,看看還有哪些其他選擇。一旦賞金時間結束,您將獲得當之無愧的快樂!非常感謝你的努力 –

相關問題