先上图
花瓣效果
整个动画动效图
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];
}
}
至此完成这个动作
有更好的方式的同学可以互相探讨
网友评论