一、簡介
POP 動(dòng)畫極為流暢,其秘密就在于這個(gè) Engine 中的POPAnimator 里,POP 通過 CADisplayLink 高達(dá) 60 FPS 的特性,打造了一個(gè)游戲級的動(dòng)畫引擎。
源碼:https://github.com/facebook/pop
二、基本用法
POPSpringAnimation 有彈性效果的動(dòng)畫類(個(gè)人比較喜歡這個(gè))
POPBasicAnimation 基本動(dòng)畫類
POPDecayAnimation 衰減動(dòng)畫類
POPCustomAnimation 可以自定義動(dòng)畫的類
1.POPBasicAnimation
NSInteger height = CGRectGetHeight(self.view.bounds);
NSInteger width = CGRectGetWidth(self.view.bounds);
CGFloat centerX = arc4random() % width;
CGFloat centerY = arc4random() % height;
POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(centerX, centerY)];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
anim.duration = 0.4;
[self.testView pop_addAnimation:anim forKey:@"centerAnimation"];
2.POPSpringAnimation
1.springBounciness 彈簧彈力 取值范圍為[0, 20],默認(rèn)值為4
2.springSpeed 彈簧速度,速度越快,動(dòng)畫時(shí)間越短 [0, 20],默認(rèn)為12,和springBounciness一起決定著彈簧動(dòng)畫的效果
3.dynamicsTension 彈簧的張力
4.dynamicsFriction 彈簧摩擦
5.dynamicsMass 質(zhì)量 。張力,摩擦,質(zhì)量這三者可以從更細(xì)的粒度上替代springBounciness和springSpeed
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
NSInteger height = CGRectGetHeight(self.view.bounds);
NSInteger width = CGRectGetWidth(self.view.bounds);
CGFloat centerX = arc4random() % width;
CGFloat centerY = arc4random() % height;
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(centerX, centerY)];
anim.springBounciness = 16;
anim.springSpeed = 6;
[self.testView pop_addAnimation:anim forKey:@"center"];
3.POPDecayAnimation
velocity 也是必須和你操作的屬性有相同的結(jié)構(gòu),如果你操作的是 bounds,想實(shí)現(xiàn)一個(gè)水滴滴到桌面的擴(kuò)散效果,那么應(yīng)該是 [NSValue valueWithCGRect:CGRectMake(0, 0,20.0, 20.0)]
如果 velocity 是負(fù)值,那么就會(huì)反向遞減。
deceleration (負(fù)加速度) 是一個(gè)你會(huì)很少用到的值,默認(rèn)是就是我們地球的 0.998
POPDecayAnimation *anim = [POPDecayAnimation animWithPropertyNamed:kPOPLayerPositionX];
anim.velocity = @(100.0);
anim.fromValue = @(25.0);
//anim.deceleration = 0.998;
anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
if (finished) {NSLog(@"Stop!");}};
三、發(fā)布界面的彈出效果
#import "XMGPublishViewController.h"
#import "TWVerticalButton.h"
#import "TWPostWordViewController.h"
#import "TWPostBlogViewController.h"
#import "TWPostPictureViewController.h"
#import "TWNavigationController.h"
#import <POP.h>
#import <AFNetworking.h>
#import <SVProgressHUD.h>
static CGFloat const XMGAnimationDelay = 0.1;
static CGFloat const XMGSpringFactor = 10;
@interface XMGPublishViewController ()
@end
@implementation XMGPublishViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self cheakNetworkStatus];
// 讓控制器的view不能被點(diǎn)擊
self.view.userInteractionEnabled = NO;
// 數(shù)據(jù)
NSArray *images = @[@"publish-text", @"publish-picture", @"publish-text"];
NSArray *titles = @[@"發(fā)說說", @"發(fā)圖片", @"發(fā)日志"];
// 中間的6個(gè)按鈕
int maxCols = 3;
CGFloat buttonW = 72;
CGFloat buttonH = buttonW + 30;
CGFloat buttonStartY = (TWScreenH - buttonH) * 0.5;
CGFloat buttonStartX = 20;
CGFloat xMargin = (TWScreenW - 2 * buttonStartX - maxCols * buttonW) / (maxCols - 1);
for (int i = 0; i<images.count; i++) {
TWVerticalButton *button = [[TWVerticalButton alloc] init];
button.tag = i;
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
// 設(shè)置內(nèi)容
button.titleLabel.font = [UIFont systemFontOfSize:14];
[button setTitle:titles[i] forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:images[i]] forState:UIControlStateNormal];
// 計(jì)算X\Y
int row = i / maxCols;
int col = i % maxCols;
CGFloat buttonX = buttonStartX + col * (xMargin + buttonW);
CGFloat buttonEndY = buttonStartY + row * buttonH;
CGFloat buttonBeginY = buttonEndY - TWScreenH;
// 按鈕動(dòng)畫
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
anim.fromValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonBeginY, buttonW, buttonH)];
anim.toValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonEndY, buttonW, buttonH)];
anim.springBounciness = XMGSpringFactor;
anim.springSpeed = XMGSpringFactor;
anim.beginTime = CACurrentMediaTime() + XMGAnimationDelay * i;
[button pop_addAnimation:anim forKey:nil];
}
// 添加標(biāo)語
CGFloat centerX = TWScreenW * 0.5;
CGFloat centerEndY = TWScreenH * 0.2;
CGFloat centerBeginY = centerEndY - TWScreenH;
UIImageView *sloganView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"app_slogan"]];
sloganView.center = CGPointMake(centerX, centerBeginY);
[self.view addSubview:sloganView];
// 標(biāo)語動(dòng)畫
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(centerX, centerBeginY)];
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(centerX, centerEndY)];
anim.beginTime = CACurrentMediaTime() + images.count * XMGAnimationDelay;
anim.springBounciness = XMGSpringFactor;
anim.springSpeed = XMGSpringFactor;
[anim setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
// 標(biāo)語動(dòng)畫執(zhí)行完畢, 恢復(fù)點(diǎn)擊事件
self.view.userInteractionEnabled = YES;
}];
[sloganView pop_addAnimation:anim forKey:nil];
}
- (void)cheakNetworkStatus{
// 1.獲得網(wǎng)絡(luò)監(jiān)控的管理者
AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];
// 2.設(shè)置網(wǎng)絡(luò)狀態(tài)改變后的處理
[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
// 當(dāng)網(wǎng)絡(luò)狀態(tài)改變了, 就會(huì)調(diào)用這個(gè)block
switch (status) {
case AFNetworkReachabilityStatusUnknown: // 未知網(wǎng)絡(luò)
NSLog(@"未知網(wǎng)絡(luò)");
break;
case AFNetworkReachabilityStatusNotReachable: // 沒有網(wǎng)絡(luò)(斷網(wǎng))
[SVProgressHUD showImage:nil status:@"請連接網(wǎng)絡(luò)"];
break;
case AFNetworkReachabilityStatusReachableViaWWAN: // 手機(jī)自帶網(wǎng)絡(luò)
NSLog(@"手機(jī)自帶網(wǎng)絡(luò)");
break;
case AFNetworkReachabilityStatusReachableViaWiFi: // WIFI
NSLog(@"WIFI");
break;
}
}];
// 3.開始監(jiān)控
[mgr startMonitoring];
}
- (void)buttonClick:(UIButton *)button
{
[self cancelWithCompletionBlock:^{
if (button.tag == 0) {
TWPostWordViewController *postWord = [[TWPostWordViewController alloc] init];
TWNavigationController *nav = [[TWNavigationController alloc] initWithRootViewController:postWord];
UIViewController *root = [UIApplication sharedApplication].keyWindow.rootViewController;
[root presentViewController:nav animated:YES completion:nil];
}else if(button.tag == 1){
TWPostPictureViewController *postWord = [[TWPostPictureViewController alloc] init];
TWNavigationController *nav = [[TWNavigationController alloc] initWithRootViewController:postWord];
UIViewController *root = [UIApplication sharedApplication].keyWindow.rootViewController;
[root presentViewController:nav animated:YES completion:nil];
}else if(button.tag == 2){
TWPostBlogViewController *postWord = [[TWPostBlogViewController alloc] init];
TWNavigationController *nav = [[TWNavigationController alloc] initWithRootViewController:postWord];
UIViewController *root = [UIApplication sharedApplication].keyWindow.rootViewController;
[root presentViewController:nav animated:YES completion:nil];
}else {
}
}];
}
- (IBAction)cancel {
[self cancelWithCompletionBlock:nil];
}
/**
* 先執(zhí)行退出動(dòng)畫, 動(dòng)畫完畢后執(zhí)行completionBlock
*/
- (void)cancelWithCompletionBlock:(void (^)())completionBlock
{
// 讓控制器的view不能被點(diǎn)擊
self.view.userInteractionEnabled = NO;
int beginIndex = 2;
for (int i = beginIndex; i<self.view.subviews.count; i++) {
UIView *subview = self.view.subviews[i];
// 基本動(dòng)畫
POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
CGFloat centerY = subview.centerY + TWScreenH;
// 動(dòng)畫的執(zhí)行節(jié)奏(一開始很慢, 后面很快)
// anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(subview.centerX, centerY)];
anim.beginTime = CACurrentMediaTime() + (i - beginIndex) * XMGAnimationDelay;
[subview pop_addAnimation:anim forKey:nil];
// 監(jiān)聽最后一個(gè)動(dòng)畫
if (i == self.view.subviews.count - 1) {
[anim setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
[self dismissViewControllerAnimated:NO completion:nil];
// 執(zhí)行傳進(jìn)來的completionBlock參數(shù)
!completionBlock ? : completionBlock();
}];
}
}
}
/**
pop和Core Animation的區(qū)別
1.Core Animation的動(dòng)畫只能添加到layer上
2.pop的動(dòng)畫能添加到任何對象
3.pop的底層并非基于Core Animation, 是基于CADisplayLink
4.Core Animation的動(dòng)畫僅僅是表象, 并不會(huì)真正修改對象的frame\size等值
5.pop的動(dòng)畫實(shí)時(shí)修改對象的屬性, 真正地修改了對象的屬性
*/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self cancelWithCompletionBlock:nil];
}
@end