• POP动画[2]


    POP动画[2]

    1:定制控制器间的转场动画.

    源码有点多-_-!!

    //
    //  RootViewController.h
    //  Animation
    //
    //  Copyright (c) 2014年 Y.X. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface RootViewController : UIViewController
    
    @end
    RootViewController.h
    //
    //  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
    RootViewController.m
    //
    //  ModelViewController.h
    //  Animation
    //
    //  Copyright (c) 2014年 Y.X. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface ModelViewController : UIViewController
    
    @end
    ModelViewController.h
    //
    //  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
    ModelViewController.m
    //
    //  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
    PresentingAnimator.h
    //
    //  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
    PresentingAnimator.m
    //
    //  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.h
    //
    //  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
    DismissingAnimator.m

    2:TableView动画

    //
    //  RootTableViewController.h
    //  POPTableView
    //
    //  Copyright (c) 2014年 Y.X. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface RootTableViewController : UITableViewController
    
    @end
    RootTableViewController.h
    //
    //  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
    RootTableViewController.m
    //
    //  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.h
    //
    //  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
    PopTableViewCell.m

    这个地方才是动画效果的关键哦:).

    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个交互用状态一个都不能少哦:

    需要实现动画的代理获取按钮的实时尺寸的信息,最为关键的一步哦:

    计算一元一次方程:

  • 相关阅读:
    小程序实现无限瀑布流
    Vue H5 项目模板
    Taro使用mobx做国际化小程序
    一次国际化记录以及平铺JSON数据
    Promise(interesting)
    返回状态码
    CSS属性兼容写法
    在DOM加载之前insertScript
    关于吸烟
    前端优化措施
  • 原文地址:https://www.cnblogs.com/YouXianMing/p/3774540.html
Copyright © 2020-2023  润新知