iOS开发 花瓣动画效果

2022-05-11  本文已影响0人  我是卖报的小行家

先上图


花瓣效果

整个动画动效图


flower.gif

核心思想
创建8个同心圆,然后将圆心偏移到一定位置
上代码

1.开始并开始动画

//注:containerView为容器,承载着最开始的圆

 if (self.containerView.subviews.count !=8) {
        for ( SMBreathCircleView * container in self.containerView.subviews) {
            [container removeFromSuperview];
        }
        for (int i = 0; i<self.animationArray.count; i++) {
            SMBreathCircleView * container = [[SMBreathCircleView alloc]init];
            container.backgroundColor = UIColor.clearColor;
            [self.containerView addSubview:container];
            [container makeConstraints:^(MASConstraintMaker *make) {
                make.center.equalTo(self);
                make.width.height.equalTo(self.containerView);
            }];
            [self addAnimationWithLayer:container.layer andAnimationArray:self.animationArray[i]];
        }
        
    }else{
        int i=0;
        for (SMBreathCircleView * container in self.containerView.subviews) {
            [self addAnimationWithLayer:container.layer andAnimationArray:self.animationArray[i]];
            i++;
        }
        
    }

2.设置CABasicAnimation的toValue

我的做法是创建了一个数组,装着8个圆形视图最终的圆心
- (NSArray *)animationArray
{
    if (!_animationArray) {
        //不能直接cos(45)  180度为π 那45度为π/4 则为cos(π/4)
        CGFloat degree = [self getRadianFromDegree:360 / 8];
        CGFloat radius = self.viewFrameWidth / 2.0;
        _animationArray = @[
            [NSValue valueWithCGPoint:CGPointMake(radius, radius *2.0f-1)],//正下
            [NSValue valueWithCGPoint:CGPointMake(radius, 1)],//正上
            [NSValue valueWithCGPoint:CGPointMake(radius *2.0f-1,radius)],//正右
            [NSValue valueWithCGPoint:CGPointMake(1,radius)],//正左
            [NSValue valueWithCGPoint:CGPointMake(radius-1 + radius * cos(degree), radius+1 -radius * sin(degree))],//右上
            [NSValue valueWithCGPoint:CGPointMake(radius+1 - radius * cos(degree), radius-1 +radius * sin(degree))],//左下
            [NSValue valueWithCGPoint:CGPointMake(radius+1 - radius * cos(degree), radius+1-radius * sin(degree))], //左上
            [NSValue valueWithCGPoint:CGPointMake(radius-1 + radius * cos(degree),radius-1+ radius * sin(degree))],//右下
        ];
    }
    return _animationArray;
}

注:这里涉及到一个知识点,当我们计算三角函数时候必须要将度数转化为弧度比如 cos45 不能直接写cos(45),应该是cos(π/4)下面是度数转弧度公式

-(float)getRadianFromDegree:(float)degree
{
    return M_PI/(180/du);
}

3.给layer添加animation,并设置animation的tovalue

-(void)addAnimationWithLayer:(CALayer *)layer andAnimationArray:(id)animationValue{
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.duration = 4;
    animation.removedOnCompletion = NO;
    animation.delegate = self;
    animation.fillMode = kCAFillModeForwards;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.autoreverses = YES;
    animation.repeatCount = INFINITY;
//经测试这里必须要设置fromvalue
    animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(self.viewFrameWidth/2.0,self.viewFrameWidth/2.0)];
    animation.toValue = animationValue;
    [layer addAnimation:animation forKey:nil];
}

4.移除动画方式

- (void)removeAnimation
{
    for (SMBreathCircleView * container in self.containerView.subviews) {
        //这里选择全部移除
        [container.layer removeAllAnimations];
    }
}

5.暂停动画

- (void)pauseOnAnimation
{
    for (SMBreathCircleView * container in self.containerView.subviews) {
        //注意这里一定不要写成CACurrentMediaTime() ToLayer
        CFTimeInterval pausedTime = [container.layer convertTime:CACurrentMediaTime() fromLayer:nil];
        container.layer.speed = 0.0;
        container.layer.timeOffset = pausedTime;
    }
}

6.继续动画

-(void)continueAnimation{
    for (SMBreathCircleView * container in self.containerView.subviews) {
        CFTimeInterval pausedTime = [container.layer timeOffset];
        container.layer.speed = 1.0;
        container.layer.timeOffset = 0.0;
        container.layer.beginTime = 0.0;
        CFTimeInterval timeSincePause = [container.layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
        container.layer.beginTime = timeSincePause;
    }
}

7.反转动画

Tips:当我们想反转动画也就是说获取动画的reverse,其实方法也就是将动画的tovalue和fromvalue对换一下位置即可

-(void)showReverseAnimationWithDuration:(NSInteger)duration{
    for (int i = 0; i<self.animationArray.count; i++) {
        SMBreathCircleView * container =self.containerView.subviews [i];
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
        animation.duration = duration;
        animation.fromValue = self.animationArray[i];
        animation.toValue = [NSValue valueWithCGPoint:CGPointMake(self.viewFrameWidth/2.0,self.viewFrameWidth/2.0)];
        animation.removedOnCompletion = NO;
        animation.delegate = self;
        animation.fillMode = kCAFillModeForwards;
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        animation.autoreverses = YES;
        animation.repeatCount = INFINITY;
        [container.layer addAnimation:animation forKey:nil];
    }
    
}

至此完成这个动作
有更好的方式的同学可以互相探讨

上一篇下一篇

猜你喜欢

热点阅读