JumpStar

  • 涉及到的技术点

    • CoreAnimation的基本单位
    • 图片弹跳
    • 翻转动画
    • 我们看到的现象是:如果以一个初速度往上抛一个物体,你的感觉是物体上抛过程花费的时间短,下落花费的时间长。所以我们在做动画中需要做这些违背物理规律的事情:即把下落的时间设置得比上弹的长。
  • JumpStar动画实现的思路

    • 动画分为两个阶段:一个弹上去的阶段,一个落下来的阶段。弹上去的过程让视图绕 y 轴旋转 90 °,此时第一阶段的动画结束。在代理方法 animationDidStop 中开始第二个动画 —— 下落。在这个阶段一开始立刻替换图片, 随后在落下的同时让视图继续旋转 90°。我们要在下落动画结束之后 removeAllAnimations。
  • JumpStar动画的具体实现步骤

    • 界面布局如图所示


      JumpStar_第1张图片
      界面布局图5.png
    • ZQJumpStarView的具体代码如下

    //  ZQJumpStarView.h
    
    #import 
    
    typedef enum : NSUInteger {
        NONMark,
        Mark,
    }STATE;
    
    @interface ZQJumpStarView : UIView
    
    /** 图片的状态 */
    @property(nonatomic, assign, setter=setState:)STATE state;
    
    /** 被标记的图片 */
    @property(nonatomic,strong)UIImage *markedImage;
    
    /** 未被标记的图片 */
    @property(nonatomic, strong)UIImage *non_markedImage;
    
    /** 动画 */
    -(void)animation;
    
    @end
    
    //  ZQJumpStarView.m
    
    #import "ZQJumpStarView.h"
    
    /** 上升时间的宏 */
    #define jumpDuration 0.125
    /** 下降时间的宏 */
    #define downDuration 0.215
    
    @interface ZQJumpStarView()
    
    /** 图片View */
    @property(nonatomic, strong)UIImageView *starView;
    
    /** 阴影View */
    @property(nonatomic, strong)UIImageView *shadowView;
    
    @end
    
    @implementation ZQJumpStarView {
    
        /** 动画执行 */
        BOOL animating;
    }
    
    -(instancetype)init {
    
        self = [super init];
        if (self) {
    
        }
        return self;
    }
    
    /** 布局子视图 */
    -(void)layoutSubviews {
    
        [super layoutSubviews];
    
        self.backgroundColor = [UIColor clearColor];
    
        if (self.starView == nil) {
            self.starView = [[UIImageView alloc] initWithFrame:CGRectMake(self.bounds.size.width / 2 - (self.bounds.size.width - 6) / 2, 0, self.bounds.size.width - 6, self.bounds.size.height - 6)];
    
            self.starView.contentMode = UIViewContentModeScaleToFill;
            [self addSubview:self.starView];
        }
        if (self.shadowView == nil) {
            self.shadowView = [[UIImageView alloc] initWithFrame:CGRectMake(self.bounds.size.width / 2 - 10 / 2, self.bounds.size.height - 3, 10, 3)];
    
            self.shadowView.alpha = 0.4;
            self.shadowView.image = [UIImage imageNamed:@"shadow_new"];
            [self addSubview:self.shadowView];
        }
    }
    
    /** 图片状态的set方法 */
    -(void)setState:(STATE)state {
    
        _state = state;
        self.starView.image = _state == Mark ? _markedImage : _non_markedImage;
    }
    
    /** 动画 */
    -(void)animation {
    
        if (animating == YES) {
            return;
        }
    
        animating = YES;
    
        CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
        transformAnimation.fromValue = @(0);
        transformAnimation.toValue = @(M_PI_2);
        transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    
        CABasicAnimation *positionAnimation = [CABasicAnimation animationWithKeyPath:@"position.y"];
        positionAnimation.fromValue = @(self.starView.center.y);
        positionAnimation.toValue = @(self.starView.center.y
        - 14);
        positionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    
        CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
        animationGroup.duration = jumpDuration;
        animationGroup.fillMode = kCAFillModeForwards;
        animationGroup.removedOnCompletion = NO;
        animationGroup.delegate = self;
        animationGroup.animations = @[transformAnimation, positionAnimation];
    
        [self.starView.layer addAnimation:animationGroup forKey:@"jumpUp"];
    }
    
    /** 上升动画开始 */
    -(void)animationDidStart:(CAAnimation *)anim {
    
        if ([anim isEqual:[self.starView.layer animationForKey:@"jumpUp"]]) {
            [UIView animateWithDuration:jumpDuration delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{
                _shadowView.alpha = 0.2;
                _shadowView.bounds = CGRectMake(0, 0, _shadowView.bounds.size.width * 1.6, _shadowView.bounds.size.height);
            } completion:NULL];
        } else if ([anim isEqual:[self.starView.layer animationForKey:@"jumpDown"]]) {
    
            [UIView animateWithDuration:jumpDuration delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{
                _shadowView.alpha = 0.4;
                _shadowView.bounds = CGRectMake(0, 0, _shadowView.bounds.size.width / 1.6, _shadowView.bounds.size.height);
            } completion:NULL];
        }
    }
    
    /** 下降动画开始 */
    -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    
        if ([anim isEqual:[self.starView.layer animationForKey:@"jumpUp"]]) {
            self.state = self.state == Mark ? NONMark : Mark;
            NSLog(@"state:%ld", _state);
    
            CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
            transformAnimation.fromValue = @(M_PI_2);
            transformAnimation.toValue = @(M_PI);
            transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    
            CABasicAnimation *positionAnimation = [CABasicAnimation animationWithKeyPath:@"position.y"];
            positionAnimation.fromValue = @(self.starView.center.y - 14);
            positionAnimation.toValue = @(self.starView.center.y);
            positionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    
            CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
            animationGroup.duration = downDuration;
            animationGroup.fillMode = kCAFillModeForwards;
            animationGroup.removedOnCompletion = NO;
            animationGroup.delegate = self;
            animationGroup.animations = @[transformAnimation, positionAnimation];
    
            [self.starView.layer addAnimation:animationGroup forKey:@"jumpDown"];
        } else if ([anim isEqual:[self.starView.layer animationForKey:@"jumpDown"]]) {
    
            [self.starView.layer removeAllAnimations];
            animating = NO;
        }
    }
    
    @end
    
    • ViewController的具体代码如下
    //  ViewController.m
    
    #import "ViewController.h"
    #import "ZQJumpStarView.h"
    
    @interface ViewController ()
    
    /** 动画View */
    @property (weak, nonatomic) IBOutlet ZQJumpStarView *jumpStarView;
    
    @end
    
    @implementation ViewController
    
    -(void)viewDidLoad {
        [super viewDidLoad];
    
        [_jumpStarView layoutIfNeeded];
        _jumpStarView.markedImage = [UIImage imageNamed:@"icon_star_incell"];
        _jumpStarView.non_markedImage = [UIImage imageNamed:@"blue_dot"];
        _jumpStarView.state = NONMark;
    }
    
    -(IBAction)tapped:(id)sender {
    
        [_jumpStarView animation];
    }
    @end
    
  • 运行结果如图所示

    JumpStar_第2张图片
    运行结果图5.gif

你可能感兴趣的:(JumpStar)