看到手机中天气闪电效果挺炫酷的,就想试着实现其效果,费了一番功夫,实现了大致的效果,还有许多地方需要改进.
使用到的有UIBezierPath,CAShapeLayer,CABasicAnimation,CAAnimationGroup等.
实现的大致思路,就是需要绘制出闪电的路径,包括主干路径和分支路径,最后添加动画效果.
要想绘制路径就需要知道路径的点,在网上搜索到一个方法可以得到闪电的路径的点.如下:
/**
* 设置闪电的主干的点
*/
- (void)setupLightPointArrWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint displace:(CGFloat)displace
{
CGFloat midX = startPoint.x;
CGFloat midY = startPoint.y;
[pointArr removeAllObjects];
[pointArr addObject:NSStringFromCGPoint(startPoint)];
while (midY < endPoint.y)
{
if (startPoint.x < kScreenWidth/2 )
{
midX += (arc4random()%3 - 0.5)*displace;
midY += (arc4random()%5 - 0.5)*displace;
}else
{
midX -= (arc4random()%3 - 0.5)*displace;
midY += (arc4random()%5 - 0.5)*displace;
}
[pointArr addObject:NSStringFromCGPoint(CGPointMake(midX, midY))];
}
}
其中闪电分支的获取点也是如此.
注意:其中分支的起点是主干上的点.当然也可以不是.
需要的点都已经获取到了,就需要绘制了.
/**
* 设置闪电的路径
*/
- (void)setupLightningPath
{
UIBezierPath *path = [UIBezierPath bezierPath];
[bezierPathArr addObject:path];
CGPoint point ;
for (int i = 0; i < pointArr.count; i ++)
{
point = CGPointFromString(pointArr[i]);
if (i == 0)
{
//画线,设置起点
[path moveToPoint:point];
}else
{
//设置第二个条线的终点,会自动把上一个终点当做起点
[path addLineToPoint:point];
}
NSLog(@"-----point%@ ",NSStringFromCGPoint(point));
if ([branchLightningStartPointArr containsObject:NSStringFromCGPoint(point)])
{
NSMutableArray *branchPointArr = [self setupBranchLightningPathPointWithStartPoint:CGPointMake(point.x, point.y) endPoint:CGPointMake(point.x + 100, point.y + 100) displace:1];
UIBezierPath *branchPath = [UIBezierPath bezierPath];
CGPoint branchPoint;
for (int j = 0; j < branchPointArr.count; j ++)
{
branchPoint = CGPointFromString(branchPointArr[j]);
if (j == 0)
{
//画线,设置起点
[branchPath moveToPoint:branchPoint];
}else
{
//设置第二个条线的终点,会自动把上一个终点当做起点
[branchPath addLineToPoint:branchPoint];
}
}
[bezierPathArr addObject:branchPath];
}
}
}
闪电的路径绘制完成以后就需要实现其动画效果.
/**
* 设置闪电的动画效果
*/
- (void)setupLightningAnimation
{
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation.duration = 0.2;
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
pathAnimation.repeatCount = 1;
//透明度
CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
opacityAnimation.fromValue = [NSNumber numberWithFloat:1.0];
opacityAnimation.toValue = [NSNumber numberWithFloat:0.0];
CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
groupAnimation.duration = 1.0;
groupAnimation.animations = @[[self opacityForever_Animation:0.1], pathAnimation,opacityAnimation];
groupAnimation.autoreverses = YES;
groupAnimation.repeatCount = 1;
for (int i = 0; i < bezierPathArr.count; i ++)
{
UIBezierPath *path = bezierPathArr[i];
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
pathLayer.path = path.CGPath;
pathLayer.strokeColor = [[UIColor whiteColor] CGColor];
pathLayer.fillColor = nil;
pathLayer.lineWidth = (i == 0?1.0f:0.5);
pathLayer.lineJoin = kCALineJoinMiter;
[self.layer addSublayer:pathLayer];
[pathLayer addAnimation:groupAnimation forKey:@"xxx"];
}
}
至此动画简单的闪电效果已经完成了.还有许多地方需要继续完善.
更新了demo效果如下:
上传到了Github:https://github.com/ITXIN/AnimationShow