UIView動(dòng)畫(huà)在平常的使用場(chǎng)景中比較普遍独榴,UIView的屬性改變時(shí)使用UIView動(dòng)畫(huà)過(guò)渡會(huì)比較自然谍失,用起來(lái)也比較簡(jiǎn)單琼了。
有UIViewAnimation谨究、UIViewAnimationWithBlocks恩袱、UIViewKeyframeAnimations三種實(shí)現(xiàn)方式。
1胶哲、UIViewAnimation
下面是UIViewAnimation的基本調(diào)用方法(方法已做備注):
@interface UIView(UIViewAnimation)
//開(kāi)始動(dòng)畫(huà)畔塔。傳遞的context值會(huì)傳遞給代理的start/did stop方法中。
+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;
//和beginAnimations方法成對(duì)出現(xiàn)鸯屿。代表動(dòng)畫(huà)開(kāi)始和執(zhí)行澈吨,動(dòng)畫(huà)內(nèi)容放在兩個(gè)個(gè)方法中間。
+ (void)commitAnimations;
// 設(shè)置動(dòng)畫(huà)代理碾盟,當(dāng)動(dòng)畫(huà)開(kāi)始或者結(jié)束時(shí)會(huì)發(fā)消息給代理對(duì)象棚辽。默認(rèn)是nil。
+ (void)setAnimationDelegate:(nullable id)delegate;
//動(dòng)畫(huà)即將開(kāi)始時(shí)冰肴,執(zhí)行selector屈藐,并且把beginAnimations:context:中傳入的參數(shù)傳進(jìn)selector
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;
//動(dòng)畫(huà)即將結(jié)束時(shí)榔组,執(zhí)行selector,并且把beginAnimations:context:中傳入的參數(shù)傳進(jìn)selector
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;
//動(dòng)畫(huà)的持續(xù)時(shí)間联逻,以秒為單位搓扯。默認(rèn)是0.2.
+ (void)setAnimationDuration:(NSTimeInterval)duration;
//動(dòng)畫(huà)延遲。默認(rèn)是0包归。
+ (void)setAnimationDelay:(NSTimeInterval)delay;
//默認(rèn)是now.
+ (void)setAnimationStartDate:(NSDate *)startDate;
//動(dòng)畫(huà)的節(jié)奏控制锨推。默認(rèn)是UIViewAnimationCurveEaseInOut。
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;
//動(dòng)畫(huà)重復(fù)次數(shù)公壤。默認(rèn)是0.
+ (void)setAnimationRepeatCount:(float)repeatCount;
//動(dòng)畫(huà)是否逆向運(yùn)行换可。如果是YES的話,動(dòng)畫(huà)會(huì)按照原來(lái)的運(yùn)動(dòng)軌跡逆向返回厦幅。默認(rèn)是NO沾鳄。
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;
//動(dòng)畫(huà)是否從當(dāng)前狀態(tài)開(kāi)始。默認(rèn)是NO确憨。如果為YES译荞,那么動(dòng)畫(huà)在運(yùn)行過(guò)程中當(dāng)前視圖的位置將會(huì)作為新的動(dòng)畫(huà)的開(kāi)始狀態(tài)。如果設(shè)置為NO休弃,新動(dòng)畫(huà)將使用視圖最後狀態(tài)的位置作為開(kāi)始狀態(tài)吞歼。
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;
//設(shè)置view的過(guò)渡效果, transition是設(shè)定過(guò)渡類型, cache為YES時(shí)代表使用視圖緩存。
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
//是否激活動(dòng)畫(huà)塔猾。如果是YES篙骡,就激活動(dòng)畫(huà),當(dāng)動(dòng)畫(huà)參數(shù)沒(méi)有被激活那么動(dòng)畫(huà)屬性的改變將被忽略桥帆。默認(rèn)是YES医增。
+ (void)setAnimationsEnabled:(BOOL)enabled;
#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) BOOL areAnimationsEnabled;
#else
+ (BOOL)areAnimationsEnabled;
#endif
+ (void)performWithoutAnimation:(void (NS_NOESCAPE ^)(void))actionsWithoutAnimation NS_AVAILABLE_IOS(7_0);
#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) NSTimeInterval inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#else
+ (NSTimeInterval)inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#endif
@end
UIViewAnimation使用示例:
UIImage * image = [UIImage imageNamed:@"icon1"];
[imageView setImage:image];
//動(dòng)畫(huà)開(kāi)始前視圖狀態(tài)
imageView.frame = CGRectMake(ScreenWidth/2-image.size.width/2, (ScreenHeight-image.size.height)/2,image.size.width,image.size.height);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0f];
image = [UIImage imageNamed:@"icon2"];
[imageView setImage:image];
//視圖最終狀態(tài)
imageView.frame = CGRectMake(ScreenWidth/2-25, ScreenHeight-50, 50, 50);
[UIView commitAnimations];
2慎皱、UIViewAnimationWithBlocks
UIViewAnimationWithBlocks的方法函數(shù)如下:
@interface UIView(UIViewAnimationWithBlocks)
/**
block動(dòng)畫(huà)老虫,可以設(shè)置動(dòng)畫(huà)時(shí)長(zhǎng)、動(dòng)畫(huà)延遲茫多、動(dòng)畫(huà)選項(xiàng)祈匙、動(dòng)畫(huà)結(jié)束狀態(tài)、動(dòng)畫(huà)完成后最終狀態(tài)天揖,
可根據(jù)自己實(shí)際需要選擇下面3種實(shí)現(xiàn)方式
**/
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL
//視圖過(guò)渡動(dòng)畫(huà)
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
//視圖間過(guò)渡動(dòng)畫(huà)
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview
//彈簧動(dòng)畫(huà)
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
//刪除視圖動(dòng)畫(huà)
+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray<__kindof UIView *> *)views options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))parallelAnimations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
@end
主要分為簡(jiǎn)單的block動(dòng)畫(huà)夺欲、視圖過(guò)渡動(dòng)畫(huà)、視圖間過(guò)渡動(dòng)畫(huà)今膊、彈簧動(dòng)畫(huà)和刪除動(dòng)畫(huà)些阅。
注:彈簧動(dòng)畫(huà)參數(shù)dampingRatio、velocity分別是阻尼大小斑唬、形變速度市埋。
dampingRatio:實(shí)際指彈簧動(dòng)畫(huà)的摩擦力大小黎泣。值的范圍是0.0~1.0。當(dāng)阻尼大小越小代表阻力越小缤谎,反之則阻力越大抒倚,阻力越小彈簧動(dòng)畫(huà)的幅度就越大,越大彈簧幅度就越小坷澡,與現(xiàn)實(shí)中彈簧拉伸的道理是一樣的托呕。
velocity:指彈簧的變化的速度。速度越大频敛,變化越快项郊。
下面看下不同動(dòng)畫(huà)的代碼示例:
(1)簡(jiǎn)單的block動(dòng)畫(huà)
-(void)AnimationWithSimpleBlocks{
UIImage * image = [UIImage imageNamed:@"heart"];
[imageView setImage:image];
imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2, 150+(ScreenHeight-150-image.size.height)/2,image.size.width,image.size.height);
[UIView animateWithDuration:1.0f delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
//動(dòng)畫(huà)終點(diǎn)
imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2, 150+(ScreenHeight-150-image.size.height)/2, image.size.width+20, image.size.height+20);
} completion:^(BOOL finished) {
//view最終狀態(tài)(UIView會(huì)從動(dòng)畫(huà)結(jié)束狀態(tài)轉(zhuǎn)換到此處設(shè)定的狀態(tài),在轉(zhuǎn)換過(guò)程中沒(méi)有動(dòng)畫(huà)效果)
imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2, 150+(ScreenHeight-150-image.size.height)/2,image.size.width,image.size.height);
}];
}
(2)視圖過(guò)渡動(dòng)畫(huà)示例:
-(void)AnimationWithTransitionBlocks{
UIImage * image = [UIImage imageNamed:@"heart"];
[imageView setImage:image];
imageView.frame = CGRectMake(0, (ScreenHeight-image.size.height)/2,image.size.width,image.size.height);
//帶有過(guò)渡效果
[UIView transitionWithView:imageView duration:1.5f options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
//動(dòng)畫(huà)終點(diǎn)
imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2, 150+(ScreenHeight-150-image.size.height)/2, image.size.width+20, image.size.height+20);
} completion:^(BOOL finished) {
}];
}
(3)視圖之間過(guò)渡動(dòng)畫(huà)代碼示例:
-(void)AnimationBetweenViews{
UIView *view1 = [[UIView alloc]initWithFrame:self.view.frame];
view1.backgroundColor = [UIColor yellowColor];
UIView *view2 = [[UIView alloc]initWithFrame:self.view.frame];
view2.backgroundColor = [UIColor orangeColor];
[self.view addSubview:view1];
[self.view addSubview:view2];
[UIView transitionFromView:view1 toView:view2 duration:1.5f options:UIViewAnimationOptionTransitionFlipFromLeft completion:^(BOOL finished) {
[view1 removeFromSuperview];
[view2 removeFromSuperview];
}];
}
(4)彈簧動(dòng)畫(huà)示例
-(void)SpringAnimation{
UIImage * image = [UIImage imageNamed:@"heart"];
[imageView setImage:image];
imageView.frame = CGRectMake(0, 150+(ScreenHeight-150-image.size.height)/2,image.size.width,image.size.height);
[UIView animateWithDuration:1.0f delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:0.5 options:0 animations:^{
//動(dòng)畫(huà)終點(diǎn)
imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2, 150+(ScreenHeight-150-image.size.height)/2, image.size.width+20, image.size.height+20);
} completion:^(BOOL finished) {
}];
}
運(yùn)行結(jié)果如下:
注:UIView的簡(jiǎn)單動(dòng)畫(huà)可以通過(guò)這兩種方式來(lái)實(shí)現(xiàn)斟赚,如果是比較復(fù)雜的動(dòng)畫(huà)的話使用CAKeyframeAnimations實(shí)現(xiàn)會(huì)更方便呆抑。
3、CAKeyframeAnimations
CAKeyframeAnimations函數(shù)如下:
@interface UIView (UIViewKeyframeAnimations)
//設(shè)定動(dòng)畫(huà)時(shí)長(zhǎng)汁展、動(dòng)畫(huà)延遲鹊碍、關(guān)鍵幀選項(xiàng)、關(guān)鍵幀
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
//添加關(guān)鍵幀動(dòng)畫(huà)的開(kāi)始時(shí)間食绿、幀動(dòng)畫(huà)在整個(gè)動(dòng)畫(huà)的比例
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations NS_AVAILABLE_IOS(7_0); // start time and duration are values between 0.0 and 1.0 specifying time and duration relative to the overall time of the keyframe animation
@end
代碼示例:
-(void)menuClick:(UIButton *)btn{
CGRect rect = CGRectMake(ScreenWidth/3-50, 275,0,0);
if (open) {
[UIView animateKeyframesWithDuration:duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
for (int i=0; i<iconArr.count; i++) {
[UIView addKeyframeWithRelativeStartTime:i*1.0/iconArr.count relativeDuration:1.0/iconArr.count animations:^{
UIImageView * functionBtn = (UIImageView *)[self.view viewWithTag:100+i];
functionBtn.frame = rect;
}];
}
open = NO;
} completion:nil];
}
else{
UIImage * icon1 = [UIImage imageNamed:@"functionIcon1"];
CGRect rect1 = CGRectMake(ScreenWidth/3, 130,50,50);
CGRect rect2 = CGRectMake(ScreenWidth/3+80, 210,50,50);
CGRect rect3 = CGRectMake(ScreenWidth/3+80, 290,50,50);
CGRect rect4 = CGRectMake(ScreenWidth/3, 370,50,50);
iconArr = @[icon1,icon1,icon1,icon1];
NSArray * rectArr = @[[NSValue valueWithCGRect:rect1],[NSValue valueWithCGRect:rect2],[NSValue valueWithCGRect:rect3],[NSValue valueWithCGRect:rect4]];
for (int i=0; i<4; i++) {
UIImageView * functionBtn = (UIImageView *)[self.view viewWithTag:100+i];
if (!functionBtn) {
functionBtn = [[UIImageView alloc]initWithImage:[iconArr objectAtIndex:i]];
functionBtn.tag = 100+i;
functionBtn.frame = rect;
[self.view addSubview:functionBtn];
}
}
[UIView animateKeyframesWithDuration:duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
for (int i=0; i<iconArr.count; i++) {
[UIView addKeyframeWithRelativeStartTime:i*1.0/iconArr.count relativeDuration:1.0/iconArr.count animations:^{
UIImageView * functionBtn = (UIImageView *)[self.view viewWithTag:100+i];
functionBtn.frame = [[rectArr objectAtIndex:i] CGRectValue];
}];
}
open = YES;
} completion:nil];
}
}
運(yùn)行效果: