2015-11-19 17 views
1

我有一個自定義UIView使用UIKit動態來執行動畫時,用戶點擊一個按鈕。有問題的觀點很簡單,我在layoutSubviews()手動佈局。但是,在UIKit Dynamics處於操作狀態時,每個動畫幀都會調用layoutSubviews(),並且在此期間我做出的所有佈局更改(例如,響應較高的狀態欄)都會導致動態視圖失真。如何在使用UIKit Dynamics時更新UIView佈局?

如何在UIKit Dynamics動畫正在進行時對視圖大小的變化做出響應?

更新

我創建了一個演示項目(儘管它剝奪了其非常緊密地匹配我的使用情況下,),並張貼on GitHub。故事板使用AutoLayout,但該視圖選擇AutoLayout用於佈置與translatesAutoresizingMaskIntoConstraints = false自己的子視圖。要重現這種行爲,請在模擬器中運行(我選擇了iPhone 5),然後在恆星擺動時點擊⌘Y以觀察失真。這是視圖代碼:

import UIKit 

class CustomView: UIView { 

    var swingingView: UIView! 

    var animator: UIDynamicAnimator! 
    var attachment: UIAttachmentBehavior! 

    var lastViewFrame = CGRectZero 


    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 

     self.translatesAutoresizingMaskIntoConstraints = false 

     swingingView = UIImageView(image: UIImage(named: "Star")) 
     self.addSubview(swingingView) 
    } 

    override func layoutSubviews() { 
     // Don't run for every frame of the animation. Only when responding to a layout change 
     guard self.frame != lastViewFrame else { 
      return 
     } 

     lastViewFrame = self.frame 

     swingingView.frame = CGRect(x: 0, y: self.frame.size.height/2, width: 100, height: 100) 

     // Only run this setup code once 
     if animator == nil { 
      animator = UIDynamicAnimator(referenceView: self) 

      let gravity = UIGravityBehavior(items: [swingingView]) 
      gravity.magnitude = 1.5 
      animator.addBehavior(gravity) 

      attachment = UIAttachmentBehavior(item: swingingView, 
       offsetFromCenter: UIOffset(horizontal: 0, vertical: swingingView.frame.size.height/-2), 
       attachedToAnchor: CGPoint(x: self.bounds.size.width/2, y: 0)) 
      attachment.length = CGFloat(250.0) 
      animator.addBehavior(attachment) 
     } 

     animator.updateItemUsingCurrentState(swingingView) 
    } 
} 
+0

您是否嘗試過創建'UIViewController'的自定義實例,而將您的動畫和佈局放在'viewDidLoad()'裏面?這將解決多次觸發佈局代碼的問題。 – NSGangster

+0

你可以把代碼放在這裏嗎?我認爲可能發生的事情是你的autoLayout是基於你的動畫視圖,所以當它動畫時,updateConstraints被調用,它扭曲了基於動畫的視圖。如果是這種情況,請確保您的其他視圖約束基於佈局指南頁邊距,而不是基於動畫的視圖 – NSGangster

+0

嗯,我想最好的方法是調試,如果您使用變量來設置幀。也許可以在'layoutSubviews()'中設置幀的位置設置斷點並查看哪些值正在更改。沒有我害怕的代碼,我無法得到很多幫助。 – NSGangster

回答

1

問題是您正在重新設置已旋轉視圖的frame(即應用了轉換的視圖)。 frame是父級上下文中視圖的大小。因此您無意中更改了此圖像視圖的bounds

由於您使用的默認內容模式爲.ScaleToFill,因此當圖像視圖的bounds發生更改時,此問題變得更加複雜,因此該明星變得(進一步)失真。 (注意,圖片並非以開頭爲正方形,因此我個人使用.ScaleAspectFit,但這取決於您。)

無論如何,您應該能夠通過(a)設置frame來解決此問題您首先將UIImageView添加到視圖層次結構中; (b)不要更改 layoutSubviews,而只是調整圖像視圖的center

+0

謝謝,但調整框架是故意的。在我的實際應用中,當視圖縮小時,我希望圖像實際縮小一點。有沒有辦法做到這一點? – Dov

+0

當然,只是改變了'bounds'。 「邊界」在子視圖的座標系內。 「框架」在超視圖的座標系內(應用變換之後)。 – Rob

+0

所以我要改變'bounds'和'center'並且不會有同樣改變'frame'同樣的效果?我會給它一個鏡頭。 – Dov

1

您應按照UIDynamicAnimator class reference

一個動態的動畫師會自動讀取你添加到它的每個動態項目的初始狀態(位置和 旋轉)使用func updateItemUsingCurrentState(_ item: UIDynamicItem) ,然後用 負責更新項目的狀態。如果您在將動態項目添加到動態動畫之後主動更改動態項目的狀態 ,請致電此方法以請動畫師閱讀並納入 新狀態。

+0

這是一個偉大的小費,但如果旋轉動畫過程中佈局的變化,我的觀點仍然得到扭曲。我甚至嘗試將視圖的「變換」設置爲標識,但這也不起作用。儘管如此,這個視圖只會被扭曲一次,並保持這種狀態。之前,它會在整個動畫中變形。我會一起嘗試獲得一個示例項目。 – Dov

+0

我添加了一個代碼示例的問題,以及一個完整的項目,GitHub上:https://github.com/abbeycode/LayoutDuringDynamics – Dov