iOS 类似亲宝宝app下拉刷新动画效果

iOS 类似亲宝宝app下拉刷新动画效果,最近看了下这种效果,感觉有点意思。于是就实现了一下。

方案一
采用两个背景View1、View2,三个球ball1,ball2,ball3,将ball1,ball2放到View1上,ball3放到View2上。

当动画开始的时候,开始旋转View1,当动画结束后,将ball2放到View2,接着旋转View2,依次循环。

旋转代码

- (CAAnimation *)rotateAnimation {
    //初始化一个动画
    CABasicAnimation *animation = [CABasicAnimation animation];
    //动画运动的方式,现在指定的是围绕Z轴旋转
    animation.keyPath = @"transform.rotation.z";
    //动画持续时间
    animation.duration = 0.35;
    //开始的角度
    animation.fromValue = [NSNumber numberWithFloat:0];
    //结束的角度
    animation.toValue = [NSNumber numberWithFloat:M_PI];
    //动画的运动方式
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    //是否反向移动动画
//    animation.autoreverses = YES;
    
    animation.repeatCount = 1;
    //动画的代理
    animation.delegate = self;
    //动画结束后的状态
    //animation.fillMode = kCAFillModeBackwards;
    
    animation.removedOnCompletion = YES;
    
    return animation;
}

当动画结束后,实现代理animationDidStop方法

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    CAAnimation *rotate1Animate = [self.content1ImageView.layer animationForKey:@"rotate"];
    CAAnimation *rotate2Animate = [self.content2ImageView.layer animationForKey:@"rotate"];
    if (!(rotate1Animate == anim || rotate2Animate == anim)) {
        return;
    }
    
    if (flag) {
        if (self.animationStoped) {
            return;
        }
        
        if (self.rotateIndex == 1) {
            self.rotateIndex = 0;
        } else {
            self.rotateIndex = 1;
        }
        
        [self redisplayBall];
        [self loadAnimation];
    }
}

- (void)redisplayBall {
    // 1-0-2
    if (self.rotateIndex == 0) {
        // 旋转第一个控件
        [self.content1ImageView addSubview:self.aballImageView];
        [self.content1ImageView addSubview:self.bballImageView];
        [self.content2ImageView addSubview:self.cballImageView];
    } else {
        // 旋转第二个控件
        [self.content1ImageView addSubview:self.aballImageView];
        [self.content2ImageView addSubview:self.bballImageView];
        [self.content2ImageView addSubview:self.cballImageView];
    }
    [self layoutBallFrame];
}

// 重新加载动画,效果,依次旋转View1与View2
- (void)loadAnimation {
    if (self.rotateIndex == 0) {
        [self.content1ImageView.layer addAnimation:[self rotateAnimation] forKey:@"rotate"];
    } else {
        [self.content2ImageView.layer addAnimation:[self rotateAnimation] forKey:@"rotate"];
    }
}

最终实现该效果。

方案二
采用路径动画来实现,三个球aballImageView,bballImageView,cballImageView,三个球的位置a-c-b。还有四个path,及四个半圆的path,上边两个top1Path、top2Path,下边两个bottom1Path、bottom2Path。

当动画开始是,球aballImageView按照top1Path的路径进行动画;同时球cballImageView按照bottom1Path的路径进行动画;当这次动画结束后,球cballImageView按照top2Path的路径进行动画,同时球bballImageView按照bottom2Path的路径进行动画;依次循环。

- (void)loadAnimation {
    if (!self.hasRotated) {
	// 如果是球aballImageView、cballImageView
        [self.aballImageView.layer addAnimation:[self rotateAnimation:self.top1Path] forKey:@"showPathAnimation"];
        [self.cballImageView.layer addAnimation:[self rotateAnimation:self.bottom1Path] forKey:@"showPathAnimation"];
    } else {
	// 如果是球cballImageView、bballImageView
        [self.cballImageView.layer addAnimation:[self rotateAnimation:self.top2Path] forKey:@"showPathAnimation"];
        [self.bballImageView.layer addAnimation:[self rotateAnimation:self.bottom2Path] forKey:@"showPathAnimation"];
    }
}

路径动画

- (CAAnimation *)rotateAnimation:(UIBezierPath *)path {
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    // 动画时间间隔
    animation.duration = 0.35f;
    // 重复次数为最大值
    animation.repeatCount = 1;
    animation.removedOnCompletion = NO;
    //    animation.fillMode = kCAFillModeForwards;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    animation.calculationMode = kCAAnimationPaced;
    animation.delegate = self;

    animation.path = path.CGPath;

    return animation;
}

动画结束后,重新开始动画

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    CAAnimation *aBallAnimate = [self.aballImageView.layer animationForKey:@"showPathAnimation"];
    CAAnimation *bBallAnimate = [self.bballImageView.layer animationForKey:@"showPathAnimation"];
    CAAnimation *cBallAnimate = [self.cballImageView.layer animationForKey:@"showPathAnimation"];
    if (!(aBallAnimate == anim || bBallAnimate == anim || cBallAnimate == anim)) {
        return;
    }
    
    if (flag) {
        if (self.animationStoped) {
            return;
        }
        
        if (self.hasRotated) {
            self.hasRotated = NO;
            [self.bballImageView.layer removeAnimationForKey:@"showPathAnimation"];
        } else {
            self.hasRotated = YES;
            [self.aballImageView.layer removeAnimationForKey:@"showPathAnimation"];
        }
        
        [self loadAnimation];
    }
}

注意点:
当使用CAKeyframeAnimation动画时,我们需要设置animation.fillMode = kCAFillModeRemoved;
动画结束后,回到原先状态,这样的,三个球的位置依然是a-c-b,这个时候开始后面的动画就可以对c、b球进行动画。

fillMode可以的值
定义定时对象在其活动持续时间之外的行为方式,本地时间可以限制在活动持续时间的任何一端,或者可以从演示文稿中删除元素。值分别是“后退”、“前进”、“两者”和“删除”。默认为移除

大意:fillMode的作用就是决定当前对象过了非active时间段的行为. 比如动画开始之前,动画结束之后
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
kCAFillModeBackwards 这个和kCAFillModeForwards是相对的,就是在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始.你可以这样设定测试代码,将一个动画加入一个layer的时候延迟5秒执行.然后就会发现在动画没有开始的时候,只要动画被加入了layer,layer便处于动画初始状态
kCAFillModeBoth 理解了上面两个,这个就很好理解了,这个其实就是上面两个的合成.动画

所以默认就是kCAFillModeRemoved,恢复动画开始前的状态。

你可能感兴趣的:(移动开发,iphone开发,Objective-c,ios,动画)