POP动画[2]
1:定制控制器间的转场动画.
源码有点多-_-!!
// // RootViewController.h // Animation // // Copyright (c) 2014年 Y.X. All rights reserved. // #import <UIKit/UIKit.h> @interface RootViewController : UIViewController @end
// // RootViewController.m // Animation // // Copyright (c) 2014年 Y.X. All rights reserved. // #import "RootViewController.h" #import "ModelViewController.h" #import "PresentingAnimator.h" #import "DismissingAnimator.h" #import "POP.h" @interface RootViewController ()<UIViewControllerTransitioningDelegate> @end @implementation RootViewController - (void)viewDidLoad { [super viewDidLoad]; UIButton *presentButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 150, 50)]; [self.view addSubview:presentButton]; presentButton.center = self.view.center; presentButton.layer.cornerRadius = 5.f; presentButton.backgroundColor = [UIColor redColor]; [presentButton setTitle:@"推出控制器" forState:UIControlStateNormal]; // 添加button事件 [presentButton addTarget:self action:@selector(present:) forControlEvents:UIControlEventTouchUpInside]; } - (void)present:(id)sender { // 推出控制器 ModelViewController *modalViewController = [ModelViewController new]; // 设置转场动画代理 modalViewController.transitioningDelegate = self; // 定制转场动画 modalViewController.modalPresentationStyle = UIModalPresentationCustom; [self.navigationController presentViewController:modalViewController animated:YES completion:NULL]; } #pragma mark - UIViewControllerTransitioningDelegate - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { // 推出控制器的动画 return [PresentingAnimator new]; } - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed { // dismissing控制器的动画 return [DismissingAnimator new]; } @end
// // ModelViewController.h // Animation // // Copyright (c) 2014年 Y.X. All rights reserved. // #import <UIKit/UIKit.h> @interface ModelViewController : UIViewController @end
// // ModelViewController.m // Animation // // Copyright (c) 2014年 Y.X. All rights reserved. // #import "ModelViewController.h" @interface ModelViewController () @end @implementation ModelViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.layer.cornerRadius = 8.f; self.view.backgroundColor = [UIColor blackColor]; [self addDismissButton]; } - (void)addDismissButton { UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeSystem]; dismissButton.translatesAutoresizingMaskIntoConstraints = NO; dismissButton.tintColor = [UIColor whiteColor]; dismissButton.titleLabel.font = [UIFont fontWithName:@"Avenir" size:20]; [dismissButton setTitle:@"Dismiss" forState:UIControlStateNormal]; [dismissButton addTarget:self action:@selector(dismiss:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:dismissButton]; // 自动布局 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:dismissButton attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f]]; // 自动布局 [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[dismissButton]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(dismissButton)]]; } - (void)dismiss:(id)sender { [self dismissViewControllerAnimated:YES completion:nil]; } @end
// // PopAnimator.h // Popping // // Created by André Schneider on 14.05.14. // Copyright (c) 2014 André Schneider. All rights reserved. // #import <Foundation/Foundation.h> @interface PresentingAnimator : NSObject <UIViewControllerAnimatedTransitioning> @end
// // PopAnimator.m // Popping // // Created by André Schneider on 14.05.14. // Copyright (c) 2014 André Schneider. All rights reserved. // #import "PresentingAnimator.h" #import "POP.h" @implementation PresentingAnimator // 转场动画时间 - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5f; } - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext { // 获取原始控制器的View UIView *fromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view; fromView.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed; fromView.userInteractionEnabled = NO; // 获取推出控制器的View UIView *toView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view; toView.frame = CGRectMake(0, 0, CGRectGetWidth(transitionContext.containerView.bounds) - 104.f, CGRectGetHeight(transitionContext.containerView.bounds) - 288.f); // 设置toView的初始的位置 toView.center = CGPointMake(transitionContext.containerView.center.x, -transitionContext.containerView.center.y); // 用来让背景变暗的动画效果 UIView *dimmingView = [[UIView alloc] initWithFrame:fromView.bounds]; dimmingView.backgroundColor = [UIColor blackColor]; dimmingView.layer.opacity = 0.0; // 添加的转场动画容器当中 [transitionContext.containerView addSubview:dimmingView]; [transitionContext.containerView addSubview:toView]; // 位置动画(Spring系列) POPSpringAnimation *positionAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionY]; positionAnimation.toValue = @(transitionContext.containerView.center.y); positionAnimation.springBounciness = 10; [positionAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) { // 动画结束后记得设置这个参数 [transitionContext completeTransition:YES]; }]; // 缩放动画(Spring系列) POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY]; scaleAnimation.springBounciness = 20; scaleAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(1.2, 1.4)]; // 透明度动画(基本动画系列) POPBasicAnimation *opacityAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerOpacity]; opacityAnimation.toValue = @(0.7); // 添加动画 [toView.layer pop_addAnimation:positionAnimation forKey:@"positionAnimation"]; [toView.layer pop_addAnimation:scaleAnimation forKey:@"scaleAnimation"]; [dimmingView.layer pop_addAnimation:opacityAnimation forKey:@"opacityAnimation"]; } @end
// // DismissingAnimator.h // Popping // // Created by André Schneider on 16.05.14. // Copyright (c) 2014 André Schneider. All rights reserved. // #import <Foundation/Foundation.h> @interface DismissingAnimator : NSObject <UIViewControllerAnimatedTransitioning> @end
// // DismissingAnimator.m // Popping // // Created by André Schneider on 16.05.14. // Copyright (c) 2014 André Schneider. All rights reserved. // #import "DismissingAnimator.h" #import "POP.h" @implementation DismissingAnimator // 转场动画时间 - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5f; } - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext { /* - 在Dismiss动画中,transitionContext.containerView.subviews里面包含了 - 之前添加进去的View哦,这点很重要 */ // 开启toVC的用户交互 UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; toVC.view.tintAdjustmentMode = UIViewTintAdjustmentModeNormal; toVC.view.userInteractionEnabled = YES; UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; // 找到刚刚的那个用于改变透明度的View __block UIView *dimmingView; [transitionContext.containerView.subviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) { if (view.layer.opacity < 1.f) { dimmingView = view; *stop = YES; } }]; // 改变透明度动画(基本动画类型) POPBasicAnimation *opacityAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerOpacity]; opacityAnimation.toValue = @(0.0); // 改变位置动画(基本类型) POPBasicAnimation *offscreenAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionY]; offscreenAnimation.toValue = @(-fromVC.view.layer.position.y); [offscreenAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) { // 通知动画结束 [transitionContext completeTransition:YES]; }]; // 执行动画 [fromVC.view.layer pop_addAnimation:offscreenAnimation forKey:@"offscreenAnimation"]; [dimmingView.layer pop_addAnimation:opacityAnimation forKey:@"opacityAnimation"]; } @end
2:TableView动画
// // RootTableViewController.h // POPTableView // // Copyright (c) 2014年 Y.X. All rights reserved. // #import <UIKit/UIKit.h> @interface RootTableViewController : UITableViewController @end
// // RootTableViewController.m // POPTableView // // Copyright (c) 2014年 Y.X. All rights reserved. // #import "RootTableViewController.h" #import "PopTableViewCell.h" @interface RootTableViewController () @end @implementation RootTableViewController - (void)viewDidLoad { [super viewDidLoad]; } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 50; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *resuseID = @"YouXianMing"; PopTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:resuseID]; if (cell == nil) { cell = [[PopTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:resuseID]; } cell.showTitle.text = @"YouXianMing"; cell.selectionStyle = UITableViewCellSelectionStyleNone; return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 50; } @end
// // PopTableViewCell.h // POPTableView // // Copyright (c) 2014年 Y.X. All rights reserved. // #import <UIKit/UIKit.h> @interface PopTableViewCell : UITableViewCell @property (nonatomic, strong) UILabel *showTitle; @end
// // PopTableViewCell.m // POPTableView // // Copyright (c) 2014年 Y.X. All rights reserved. // #import "PopTableViewCell.h" #import "POP.h" @implementation PopTableViewCell - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { _showTitle = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 50)]; [self addSubview:_showTitle]; _showTitle.textAlignment = NSTextAlignmentCenter; _showTitle.font = [UIFont fontWithName:@"HelveticaNeue-Thin" size:20.f]; } return self; } - (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { [super setHighlighted:highlighted animated:animated]; if (self.highlighted) { // 选中时动画 POPBasicAnimation *scaleAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewScaleXY]; scaleAnimation.duration = 0.1; scaleAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(0.85, 0.85)]; [_showTitle pop_addAnimation:scaleAnimation forKey:@"scaleAnimation"]; } else { // 没有选中或者再次显示时的动画 POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewScaleXY]; scaleAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(1, 1)]; scaleAnimation.velocity = [NSValue valueWithCGPoint:CGPointMake(3, 3)]; scaleAnimation.springBounciness = 20.f; [_showTitle pop_addAnimation:scaleAnimation forKey:@"scaleAnimation"]; } } @end
这个地方才是动画效果的关键哦:).
3:高逼格按钮动画
// // RootViewController.m // ButtonAnimation // // Copyright (c) 2014年 Y.X. All rights reserved. // #import "RootViewController.h" #import "CAShapeLayer+Circle.h" #import "POP.h" @interface RootViewController ()<POPAnimationDelegate> @property (nonatomic, strong) UIButton *button; @property (nonatomic, strong) CAShapeLayer *circleShape1; @property (nonatomic, strong) CAShapeLayer *circleShape2; @end @implementation RootViewController - (void)viewDidLoad { [super viewDidLoad]; // 圆环1 _circleShape1 = [CAShapeLayer LayerWithCircleCenter:self.view.center radius:70.f startAngle:DEGREES(0) endAngle:DEGREES(360) clockwise:YES lineDashPattern:nil]; _circleShape1.lineWidth = 3.f; _circleShape1.strokeColor = [UIColor cyanColor].CGColor; _circleShape1.strokeEnd = 0.f; [self.view.layer addSublayer:_circleShape1]; // 圆环2 _circleShape2 = [CAShapeLayer LayerWithCircleCenter:self.view.center radius:90.f startAngle:DEGREES(0) endAngle:DEGREES(360) clockwise:NO lineDashPattern:nil]; _circleShape2.lineWidth = 1.f; _circleShape2.strokeColor = [UIColor magentaColor].CGColor; _circleShape2.strokeEnd = 0.f; [self.view.layer addSublayer:_circleShape2]; // 完整显示按住按钮后的动画效果 _button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; _button.layer.cornerRadius = 50.f; _button.backgroundColor = [UIColor cyanColor]; _button.center = self.view.center; [self.view addSubview:_button]; // 按住按钮后没有松手的动画 [_button addTarget:self action:@selector(scaleToSmall) forControlEvents:UIControlEventTouchDown | UIControlEventTouchDragEnter]; // 按住按钮松手后的动画 [_button addTarget:self action:@selector(scaleAnimations) forControlEvents:UIControlEventTouchUpInside]; // 按住按钮后拖拽出去的动画 [_button addTarget:self action:@selector(scaleToDefault) forControlEvents:UIControlEventTouchDragExit]; } - (void)scaleToSmall { // 变小尺寸 POPBasicAnimation *scaleAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY]; scaleAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(0.7f, 0.7f)]; scaleAnimation.delegate = self; // 核心 [_button.layer pop_addAnimation:scaleAnimation forKey:nil]; // 颜色 POPSpringAnimation *backgroundColor = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBackgroundColor]; backgroundColor.toValue = (id)[UIColor magentaColor].CGColor; [_button.layer pop_addAnimation:backgroundColor forKey:@"magentaColor"]; } - (void)scaleAnimations { // 恢复尺寸 POPBasicAnimation *scaleAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY]; scaleAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(1.f, 1.f)]; scaleAnimation.delegate = self; // 核心 [_button.layer pop_addAnimation:scaleAnimation forKey:nil]; // 颜色 POPSpringAnimation *backgroundColor = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBackgroundColor]; backgroundColor.toValue = (id)[UIColor cyanColor].CGColor; [_button.layer pop_removeAnimationForKey:@"magentaColor"]; // 先移除再添加 [_button.layer pop_addAnimation:backgroundColor forKey:nil]; } - (void)scaleToDefault { // 恢复尺寸 POPBasicAnimation *scaleAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY]; scaleAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(1.f, 1.f)]; scaleAnimation.delegate = self; // 核心 [_button.layer pop_addAnimation:scaleAnimation forKey:nil]; // 颜色 POPSpringAnimation *backgroundColor = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBackgroundColor]; backgroundColor.toValue = (id)[UIColor cyanColor].CGColor; [_button.layer pop_removeAnimationForKey:@"magentaColor"]; // 先移除再添加 [_button.layer pop_addAnimation:backgroundColor forKey:nil]; } // 代理 - (void)pop_animationDidApply:(POPAnimation *)anim { NSValue *toValue = (NSValue *)[anim valueForKeyPath:@"currentValue"]; CGSize size = [toValue CGSizeValue]; _circleShape1.strokeEnd = (size.height - calculateConstant(0, 1, 1, 0.7))/calculateSlope(0, 1, 1, 0.7); _circleShape2.strokeEnd = (size.height - calculateConstant(0, 1, 1, 0.7))/calculateSlope(0, 1, 1, 0.7); } CGFloat calculateSlope(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) { return (y2 - y1) / (x2 - x1); } CGFloat calculateConstant(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) { return (y1*(x2 - x1) - x1*(y2 - y1)) / (x2 - x1); } @end
几个非常核心的地方:
按钮的3个交互用状态一个都不能少哦:
需要实现动画的代理获取按钮的实时尺寸的信息,最为关键的一步哦:
计算一元一次方程: