是的,很明確的告訴各位看官,AutoLayout的確能做動畫。AutoLayout是用來做各種約束,是用來適配不同螢幕的,那麼當我們改變其中某些約束並講這個改變的過程以緩慢的速度顯示,那麼是不是就實現了動畫~
先來看一個酷炫的動畫,這個動畫由書籍iOS Animations by tutorials提供:
由書籍iOS Animations by tutorials提供
接下來我們將圍繞這個動畫的實現過程來進行敘述。
首先給我們最上方的這個類似Navigation的menu做動畫,很明顯我們在這裡是改變了這個view的Height,既然如此,我們首先要做的就是擷取這個menuView的約束條件,我們在代碼中添加以下一行:
@IBOutlet var menuHeightConstraint: NSLayoutConstraint!
如何給約束條件做關聯,首先找到我們的約束條件:
這個就是我們的menuView的高度的約束條件
雙擊這個約束條件,然後選擇Connections Inspector,如下圖操作:
1.png
然後選擇menuHeightConstraint,這樣我們就給約束條件做了一個關聯。
現在我們在那個“+”按鈕的方法裡添加以下代碼:
isMenuOpen = !isMenuOpen
menuHeightConstraint.constant = isMenuOpen ? 200.0 : 60.0
titleLabel.text = isMenuOpen ? "Select Item" : "Packing List"
UIView.animateWithDuration(1.0, delay: 0.0,
usingSpringWithDamping: 0.4, initialSpringVelocity: 10.0,
options: .CurveEaseIn, animations: {
self.view.layoutIfNeeded()
let angle = self.isMenuOpen ? CGFloat(M_PI_4) : 0.0
self.buttonMenu.transform = CGAffineTransformMakeRotation(angle)
}, completion: nil)
我們來看一下效果,我可以看到menuView很拽的下來了,還duang~duang~duang~的。這段代碼在上一篇我們大多都講過了,除了這個函數:
self.view.layoutIfNeeded()
這個函數是什麼意思呢,你可以這樣理解,AutoLayout對於約束試一次計算,一次實現,但是當你加上這個函數以後,View還是一次實現了~~~額~~~但是,iOS沒有機會去重新整理視圖,所有就會有動畫的效果。~這一點好像和那個很廢的包,java裡的‘swing’有點類似~~~
對於 UIView.animateWithDuration這個函數若是有什麼不懂的,請自行參考我的上一篇文章。
很多時候,我們不能或者不想給我們的約束做一個關聯,那麼這個時候我們如何擷取我們的約束從而改變他呢?我們這裡有一個函數.constraints()這個函數返回一個數組,這個數組中有這個控制項的所有的約束。接下來我們給標題添加動畫,我們上面看到,動畫中標題duang~的一下跑到了左邊。
for constraint in titleLabel.superview!.constraints() as! [NSLayoutConstraint] {
if constraint.secondItem as? NSObject == titleLabel && constraint.secondAttribute == .CenterX {
constraint.constant = isMenuOpen ? 100.0 : 0.0
continue
}
}
在這段代碼中我們用前面提到的那個函數.constraints()擷取了所有約束,然後用一個迴圈挨個檢查,用if語句來尋找我們想要改變的約束。然後~~然後改變咯。
當然你也可以通過添加約束的方式來增加動畫,如何添加約束,這裡就不多說了,大體實現動畫的方式和上面類似,你只需要添加self.view.layoutIfNeeded()這個神奇的函數。
接下來的任務是添加那個橫著的menu,就是那個有好多沙灘褲,還有一條比基尼的那個橫幅。
override func didMoveToSuperview() {
super.didMoveToSuperview()
if superview == nil {
return
}
UIView.animateWithDuration(1.0, delay: 0.01, usingSpringWithDamping: 0.5, initialSpringVelocity: 10.0, options: .CurveEaseIn, animations: {
self.alpha = 1.0
self.center.x -= self.frame.size.width
}, completion: nil)
}
這個slider是HorizontalItemList類的,而這個HorizontalItemList類繼承自UIScrollView,然後我們在他的
override func didMoveToSuperview()
函數中添加動畫,那麼當這個UI空間添加到view的時候就會執行這個動畫,而至於這個動畫實現則是非常簡單,我們用很簡單的函數,實現了很酷炫的動畫。
最終任務:當點擊列表的時候,在視圖下方顯示頭像。
我們來理一下邏輯,我們首相要做的就是建立出個映像,然後給他約束,然後改變他的約束,以此來實現動畫。
func showItem(index: Int) {
println("tapped item (index)")
//1
let imageView = UIImageView(image: UIImage(named: "summericons_100px_0(index).png"))
// imageView.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5)
imageView.layer.cornerRadius = 5.0
imageView.layer.masksToBounds = true
imageView.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(imageView)
let conX = NSLayoutConstraint(
item: imageView,
attribute: .CenterX,
relatedBy: .Equal,
toItem: view,
attribute: .CenterX,
multiplier: 1.0,
constant: 0.0)
conX.active = true
let conY = NSLayoutConstraint(
item: imageView,
attribute: .Bottom,
relatedBy: .Equal,
toItem: view,
attribute: .Bottom,
multiplier: 1.0,
constant: imageView.frame.size.height)
conY.active = true
let conWidth = NSLayoutConstraint(
item: imageView,
attribute: .Width,
relatedBy: .Equal,
toItem: view,
attribute: .Width,
multiplier: 0.33,
constant: -50.0)
conWidth.active = true
let conHeight = NSLayoutConstraint(
item: imageView,
attribute: .Height,
relatedBy: .Equal,
toItem: imageView,
attribute: .Width,
multiplier: 1.0,
constant: 0.0)
conHeight.active = true
view.layoutIfNeeded()
//2
UIView.animateWithDuration(0.8, delay: 0.0,
usingSpringWithDamping: 0.4, initialSpringVelocity: 0.0,
options: nil, animations: {
conY.constant = -imageView.frame.size.height/2
conWidth.constant = 0.0
self.view.layoutIfNeeded()
}, completion: nil)
UIView.animateWithDuration(0.8, delay: 1.0, options: nil, animations: {
conY.constant = imageView.frame.size.height
conWidth.constant = -50.0
self.view.layoutIfNeeded()
}, completion: {_ in
imageView.removeFromSuperview()
})
}
}
來解釋一下這段代碼:
//1 建立了四個約束,包括conY、conX、conHeight、conHeight。
//2 通過修改約束來實現動畫,前面已經講過了。
那麼現在唯一令大家疑惑的可能只有穿件約束的那些個屬性了,我們拿第一個來舉例:
let conX = NSLayoutConstraint(
item: imageView,
attribute: .CenterX,
relatedBy: .Equal,
toItem: view,
attribute: .CenterX,
multiplier: 1.0,
constant: 0.0)
conX.active = true
item:約束的第一個對象。
attribute:第一個對象的屬性。
relatedBy: 約束的一些其他作用,在這裡只用.Equal。
toItem: 約束的第二個對象。
attribute: 第二個對象的屬性。
multiplier: 乘數。
constant: 約束的值。
好的我們基本實現了所有的酷酷的動畫。
終結一下就是改變約束條件,配合上函數self.view.layoutIfNeeded()。