是的,很明確的告訴各位看官谴蔑,AutoLayout的確能做動(dòng)畫(huà)豌骏。AutoLayout是用來(lái)做各種約束,是用來(lái)適配不同屏幕的隐锭,那么當(dāng)我們改變其中某些約束并講這個(gè)改變的過(guò)程以緩慢的速度顯示窃躲,那么是不是就實(shí)現(xiàn)了動(dòng)畫(huà)~
先來(lái)看一個(gè)酷炫的動(dòng)畫(huà),這個(gè)動(dòng)畫(huà)由書(shū)籍iOS Animations by tutorials提供:
接下來(lái)我們將圍繞這個(gè)動(dòng)畫(huà)的實(shí)現(xiàn)過(guò)程來(lái)進(jìn)行敘述钦睡。
首先給我們最上方的這個(gè)類似Navigation的menu做動(dòng)畫(huà)蒂窒,很明顯我們?cè)谶@里是改變了這個(gè)view的Height,既然如此荞怒,我們首先要做的就是獲取這個(gè)menuView的約束條件洒琢,我們?cè)诖a中添加以下一行:
@IBOutlet var menuHeightConstraint: NSLayoutConstraint!
如何給約束條件做關(guān)聯(lián),首先找到我們的約束條件:
雙擊這個(gè)約束條件褐桌,然后選擇Connections Inspector衰抑,如下圖操作:
然后選擇menuHeightConstraint,這樣我們就給約束條件做了一個(gè)關(guān)聯(lián)呛踊。
現(xiàn)在我們?cè)谀莻€(gè)“+”按鈕的方法里添加以下代碼:
<pre><code>
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)
</code></pre>
我們來(lái)看一下效果谭网,我可以看到menuView很拽的下來(lái)了,還duang~duang~duang~的赃春。這段代碼在上一篇我們大多都講過(guò)了愉择,除了這個(gè)函數(shù):
self.view.layoutIfNeeded()
這個(gè)函數(shù)是什么意思呢,你可以這樣理解,AutoLayout對(duì)于約束試一次計(jì)算薄辅,一次實(shí)現(xiàn)要拂,但是當(dāng)你加上這個(gè)函數(shù)以后抠璃,View還是一次實(shí)現(xiàn)了~~~額~~~但是站楚,iOS沒(méi)有機(jī)會(huì)去刷新視圖,所有就會(huì)有動(dòng)畫(huà)的效果搏嗡×海~這一點(diǎn)好像和那個(gè)很廢的包采盒,java里的‘swing’有點(diǎn)類似~~~
對(duì)于** UIView.animateWithDuration**這個(gè)函數(shù)若是有什么不懂的磅氨,請(qǐng)自行參考我的上一篇文章。
很多時(shí)候延赌,我們不能或者不想給我們的約束做一個(gè)關(guān)聯(lián)挫以,那么這個(gè)時(shí)候我們?nèi)绾潍@取我們的約束從而改變他呢窃祝?我們這里有一個(gè)函數(shù).constraints()這個(gè)函數(shù)返回一個(gè)數(shù)組粪小,這個(gè)數(shù)組中有這個(gè)控件的所有的約束探膊。接下來(lái)我們給標(biāo)題添加動(dòng)畫(huà)突想,我們上面看到,動(dòng)畫(huà)中標(biāo)題duang~的一下跑到了左邊袭灯。
<pre><code>
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
}
}
</code></pre>
在這段代碼中我們用前面提到的那個(gè)函數(shù).constraints()獲取了所有約束绑嘹,然后用一個(gè)循環(huán)挨個(gè)檢查工腋,用if語(yǔ)句來(lái)尋找我們想要改變的約束畅卓。然后~~然后改變咯蟋恬。
當(dāng)然你也可以通過(guò)添加約束的方式來(lái)增加動(dòng)畫(huà),如何添加約束拜马,這里就不多說(shuō)了俩莽,大體實(shí)現(xiàn)動(dòng)畫(huà)的方式和上面類似扮超,你只需要添加self.view.layoutIfNeeded()這個(gè)神奇的函數(shù)出刷。
接下來(lái)的任務(wù)是添加那個(gè)橫著的menu括尸,就是那個(gè)有好多沙灘褲濒翻,還有一條比基尼的那個(gè)橫幅有送。
<pre><code>
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)
}
</code></pre>
這個(gè)slider是HorizontalItemList類的雀摘,而這個(gè)HorizontalItemList類繼承自UIScrollView,然后我們?cè)谒?/p>
override func didMoveToSuperview()
函數(shù)中添加動(dòng)畫(huà)涯塔,那么當(dāng)這個(gè)UI空間添加到view的時(shí)候就會(huì)執(zhí)行這個(gè)動(dòng)畫(huà)清蚀,而至于這個(gè)動(dòng)畫(huà)實(shí)現(xiàn)則是非常簡(jiǎn)單枷邪,我們用很簡(jiǎn)單的函數(shù),實(shí)現(xiàn)了很酷炫的動(dòng)畫(huà)。
最終任務(wù):當(dāng)點(diǎn)擊列表的時(shí)候腹泌,在視圖下方顯示頭像。
我們來(lái)理一下邏輯尔觉,我們首相要做的就是創(chuàng)建出個(gè)圖像凉袱,然后給他約束穷娱,然后改變他的約束绑蔫,以此來(lái)實(shí)現(xiàn)動(dòng)畫(huà)泵额。
<pre><code>
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()
})
}
}
</code></pre>
來(lái)解釋一下這段代碼:
- //1 創(chuàng)建了四個(gè)約束,包括conY携添、conX、conHeight烈掠、conHeight左敌。
- //2 通過(guò)修改約束來(lái)實(shí)現(xiàn)動(dòng)畫(huà),前面已經(jīng)講過(guò)了。
那么現(xiàn)在唯一令大家疑惑的可能只有穿件約束的那些個(gè)屬性了叼风,我們拿第一個(gè)來(lái)舉例:
<pre><code>
let conX = NSLayoutConstraint(
item: imageView,
attribute: .CenterX,
relatedBy: .Equal,
toItem: view,
attribute: .CenterX,
multiplier: 1.0,
constant: 0.0)
conX.active = true
</code></pre>
- item:約束的第一個(gè)對(duì)象。
- attribute:第一個(gè)對(duì)象的屬性。
- relatedBy: 約束的一些其他作用孽鸡,在這里只用.Equal蹂午。
- toItem: 約束的第二個(gè)對(duì)象恕汇。
- attribute: 第二個(gè)對(duì)象的屬性啰脚。
- multiplier: 乘數(shù)橄镜。
- constant: 約束的值进宝。
好的我們基本實(shí)現(xiàn)了所有的酷酷的動(dòng)畫(huà)膀曾。
終結(jié)一下就是改變約束條件晶框,配合上函數(shù)self.view.layoutIfNeeded()拐纱。
所有源代碼已上傳Github:https://github.com/superxlx/iOS_Animation_Test2