3.1 Basic Animation
?
?CABasicAnimation
?
3.2 Keyframe Animations
?
與基本動(dòng)畫(huà)進(jìn)行線性插值不同,關(guān)鍵楨動(dòng)畫(huà)允許你在特定時(shí)間指定不同的數(shù)值,這樣你可以在動(dòng)畫(huà)的全過(guò)程控制動(dòng)畫(huà)的展示和動(dòng)作。
自從發(fā)明手繪電影以來(lái),關(guān)鍵楨就在動(dòng)畫(huà)中起到了一定作用。一些資深的藝術(shù)家會(huì)針對(duì)一個(gè)場(chǎng)景畫(huà)不同的關(guān)鍵楨,而一些剛?cè)胄械乃囆g(shù)家卻會(huì)填滿(mǎn)每一楨,以便使動(dòng)畫(huà)看起來(lái)更平滑。(有時(shí)候這個(gè)過(guò)程叫做tweening:兩者之間的動(dòng)畫(huà))。Core Animation的關(guān)鍵楨動(dòng)畫(huà)可以幫我們實(shí)現(xiàn)在關(guān)鍵楨之間的填充,我們只需要指定哪個(gè)是關(guān)鍵楨,系統(tǒng)會(huì)自動(dòng)幫我們生成動(dòng)畫(huà)。
另外一個(gè)很酷的東西是,關(guān)鍵楨動(dòng)畫(huà)同樣可以完成任何基本動(dòng)畫(huà)能夠完成的動(dòng)作。特別是點(diǎn)、大小或是矩形。比如如果我們希望讓一個(gè)層的不透明度顯示為一個(gè)動(dòng)畫(huà),我們可以指定一些不同的數(shù)值(比如:0.25, 0.50, 0.75),然后在動(dòng)畫(huà)的過(guò)程的不同時(shí)間中逐漸變化。
再一個(gè)真的很酷的方面,我們不光可以使用離散數(shù)值,更可以使用CGPath去指定關(guān)鍵楨動(dòng)畫(huà)的值。換句話(huà)說(shuō),我們不僅僅可以在特定時(shí)間點(diǎn)指定特定的動(dòng)畫(huà)值,還可以使用曲線路徑去指定動(dòng)畫(huà)的值。舉例說(shuō)明,我們可以將一個(gè)層的不透明度用鐘型曲線表示:開(kāi)始是透明,然后逐漸顯現(xiàn)到某個(gè)特定透明度,再逐漸變?yōu)橥该鳌N覀冞€可以用CGPoint和CGSize值的路徑做為動(dòng)畫(huà)的行進(jìn)路線。這樣,路徑的x值可以表示橫坐標(biāo)也可以表示寬度,y既可以表示縱坐標(biāo)還可以表示高度。
?
?
?
?
?
?
The code to create the keyframe animation would look like this:
?
- (CAKeyframeAnimation *)opacityAnimation { CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; animation.values = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.75], [NSNumber numberWithFloat:0.0], nil]; animation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0.25], [NSNumber numberWithFloat:0.50], [NSNumber numberWithFloat:0.75], nil]; return animation; }
?
不設(shè)置keyTimes時(shí)的運(yùn)行方式:
?
?
Keyframes and Paths
?
?
- (void)addBounceAnimation { [mover setAnimations:[NSDictionary dictionaryWithObjectsAndKeys: self.originAnimation, @"frameOrigin" , nil]]; } - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; if (self) { CGFloat xInset = 3.0f * (NSWidth(frame) / 8.0f); CGFloat yInset = 3.0f * (NSHeight(frame) / 8.0f); NSRect moverFrame = NSInsetRect(frame, xInset, yInset); mover = [[NSImageView alloc] initWithFrame:moverFrame]; [mover setImageScaling:NSScaleToFit]; [mover setImage:[NSImage imageNamed:@"photo.jpg" ]]; [self addSubview:mover]; [self addBounceAnimation]; } return self; }
?
?
[mover setAnimations:[NSDictionary dictionaryWithObjectsAndKeys:?self.originAnimation, @" frameOrigin " , nil]];
?
frameOrigin:
要和[[mover animator] setFrameOrigin:rect.origin];的
setFrameOrigin相對(duì)應(yīng),才會(huì)在setFrameOrigin方法被調(diào)用的時(shí)候,執(zhí)行設(shè)置的動(dòng)畫(huà)
例如:
- (void)awakeFromNib
{
NSView *contentView = [[self window] contentView];
[contentView setWantsLayer:YES];
[contentView addSubview:[self currentView]];
transition = [CATransition animation];
[transition setType:kCATransitionPush];
[transition setSubtype:kCATransitionFromLeft];
NSDictionary *ani = [NSDictionary dictionaryWithObject:transition
forKey:@"subviews"];
[contentView setAnimations:ani];
}
awakeFromNib首先打開(kāi)Core Animation支持(就是setWantsLayer這行)。然后把當(dāng)前的參考視圖currentView做為子視圖加入到contentView中。由于我們已經(jīng)將currentView的frameOrigin屬性設(shè)置為0,0,因此不需要考慮subview的位置。
接下來(lái)我建立了一個(gè)CATransition的動(dòng)畫(huà)。注意我在AppDelegate中將這個(gè)動(dòng)畫(huà)保留為ivar。原因很明顯,當(dāng)動(dòng)畫(huà)建立時(shí),我將它做為transition動(dòng)畫(huà)加入content view,key是“subviews”。這個(gè)transition動(dòng)畫(huà)無(wú)論在一個(gè)subview添加、刪除或者替換的時(shí)候都會(huì)觸發(fā)。
?
- (CAKeyframeAnimation *)originAnimation { CAKeyframeAnimation *originAnimation = [CAKeyframeAnimation animation]; originAnimation.path = self.heartPath; originAnimation.duration = 2.0f; originAnimation.calculationMode = kCAAnimationPaced; return originAnimation; }
?
設(shè)置動(dòng)畫(huà)運(yùn)行路徑:
???? originAnimation.path = self.heartPath;
設(shè)置動(dòng)畫(huà)持續(xù)時(shí)間:
???? originAnimation.duration = 2.0f;
設(shè)置動(dòng)畫(huà)方式:
???? originAnimation.calculationMode = kCAAnimationPaced;
?
?
設(shè)置動(dòng)畫(huà)路徑:
- (CGPathRef)heartPath { NSRect frame = [mover frame]; if(heartPath == NULL) { heartPath = CGPathCreateMutable(); CGPathMoveToPoint(heartPath, NULL, NSMinX(frame), NSMinY(frame)); CGPathAddLineToPoint(heartPath, NULL, NSMinX(frame) - NSWidth(frame),NSMinY(frame) + NSHeight(frame) * 0.85); CGPathAddLineToPoint(heartPath, NULL, NSMinX(frame),NSMinY(frame) - NSHeight(frame) * 1.5); CGPathAddLineToPoint(heartPath, NULL, NSMinX(frame) + NSWidth(frame),NSMinY(frame) + NSHeight(frame) * 0.85); CGPathAddLineToPoint(heartPath, NULL, NSMinX(frame), NSMinY(frame)); CGPathCloseSubpath(heartPath); } return heartPath; }
?
?
- (void)bounce { NSRect rect = [mover frame]; [[mover animator] setFrameOrigin:rect.origin]; }
?
Recall that since we have added an animation to the animations dictionary under the frameOrigin key, the animator will find it during its search and use ours instead of the default animation.
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
