工作中有一个需求,仿照各大音乐播放app做一个碟片旋转的效果。
后台给的图片是正常的,裁剪边框什么的还是得自己来。
终于整完了,写篇blog纪念一下。
创建一个RotateView,h文件设置两个属性:Image和Rotate。
image来赋值图片,rotate来控制是否旋转。
//重写image的setter方法
-(void)setImage:(UIImage *)image{
_image = image;
//获取正方形图片
UIImage *squarlImage = [self squarlImageWithImage:image];
//绘制环形图片
squarlImage = [self getClearRectImage:squarlImage];
//添加上边框
squarlImage = [self drawBorderWithImage:squarlImage];
//赋值
self.imageView.image = squarlImage;
}
图片不一定都是正方形的,还有长方形。这种情况需要先裁剪成正方形,我这边的需求是从center开始。
//图片做成正方形
-(UIImage *)squarlImageWithImage:(UIImage *)image{
CGFloat imageWidth = image.size.width;
CGFloat imageHeight = image.size.height;
//判断图片是否是正方形
if (imageWidth == imageHeight) {
return image;
}
//获取正方形的边长
CGFloat width = imageWidth;
if (imageHeight<imageWidth) {
width = imageHeight;
}
//从中心扩散,以最短边为边长的正方形
CGRect rect = CGRectMake((imageWidth-width)/2, (imageHeight-width)/2, width, width);
CGImageRef SquareImageRef = CGImageCreateWithImageInRect(image.CGImage,rect);
CGRect SquareImageBounds=CGRectMake(0,0,CGImageGetWidth(SquareImageRef),CGImageGetHeight(SquareImageRef));
UIGraphicsBeginImageContext(SquareImageBounds.size);
CGContextRef context =UIGraphicsGetCurrentContext();
CGContextDrawImage(context,SquareImageBounds,SquareImageRef);
UIImage* SquareImage = [UIImage imageWithCGImage:SquareImageRef];
UIGraphicsEndImageContext();
CGImageRelease(SquareImageRef);
return SquareImage;
}
这样就获取到了一张正方形图片,接下来就可以开始裁剪环形了。
- (UIImage*)getClearRectImage:(UIImage*)image{
UIGraphicsBeginImageContextWithOptions(image.size,NO,0.0f);
CGContextRef ctx =UIGraphicsGetCurrentContext();
//最外层圆的路径
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, image.size.width, image.size.height) cornerRadius:image.size.width/2];
[circlePath addClip]; // 裁剪
// 绘制图片到图片上下文中
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
[image drawAtPoint:CGPointZero];
//内部圆的半径
CGFloat bigRaduis = image.size.width/10;
CGRect cirleRect =CGRectMake(image.size.width/2-bigRaduis, image.size.height/2-bigRaduis, bigRaduis*2, bigRaduis*2);
CGContextAddEllipseInRect(ctx,cirleRect);
CGContextClip(ctx);
CGContextClearRect(ctx,cirleRect);
UIImage*newImage =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
环形图片已经有了,还差两圈白色边框
-(UIImage *)drawBorderWithImage:(UIImage *)image{
UIGraphicsBeginImageContextWithOptions(image.size,NO,0.0f);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect bigRect = CGRectMake(3,3,image.size.width-6,image.size.height-6);
//设置空心圆的线条宽度
CGContextSetLineWidth(ctx, 6);
//以矩形bigRect为依据画一个圆
CGContextAddEllipseInRect(ctx, bigRect);
//填充当前绘画区域的颜色
[[UIColor whiteColor] set];
//(如果是画圆会沿着矩形外围描画出指定宽度的(圆线)空心圆)/(根据上下文的内容渲染图层)
CGContextStrokePath(ctx);
//画一个小圆
CGFloat bigRaduis = image.size.width/10;
CGRect smallRect =CGRectMake(image.size.width/2-bigRaduis, image.size.height/2-bigRaduis, bigRaduis*2, bigRaduis*2);
//设置空心圆的线条宽度
CGContextSetLineWidth(ctx, 6);
//以矩形Rect为依据画一个圆
CGContextAddEllipseInRect(ctx, smallRect);
//填充当前绘画区域的颜色
[[UIColor whiteColor] set];
//(如果是画圆会沿着矩形外围描画出指定宽度的(圆线)空心圆)/(根据上下文的内容渲染图层)
CGContextStrokePath(ctx);
//图片绘制进去
[image drawInRect:bigRect];
UIImage*newImage =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
ok,这样就已经完成了碟片效果的图片,接下来就是让他随着播放旋转了。
重写rotate属性的setter方法来实现控制旋转开始暂停。
-(void)setIsRotate:(BOOL)isRotate{
_isRotate = isRotate;
//开始旋转
if (isRotate) {
//是否有上次暂停的时间
if (self.imageView.layer.timeOffset == 0.0) {
//没有,说明是第一次旋转
CABasicAnimation* rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotateAnimation.fromValue = [NSNumber numberWithFloat:0.0];
rotateAnimation.toValue = [NSNumber numberWithFloat:M_PI * 2]; // 旋转一周
rotateAnimation.duration = 10.0; // 旋转时间20秒
rotateAnimation.repeatCount = MAXFLOAT; // 重复次数,这里用最大次数
[self.imageView.layer addAnimation:rotateAnimation forKey:nil];
}else{
//有。说明是旋转中途暂停过,继续上次的位置来旋转
CFTimeInterval pausedTime = self.imageView.layer.timeOffset;
self.imageView.layer.speed = 1.0;
self.imageView.layer.timeOffset = 0.0;
self.imageView.layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [self.imageView.layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
self.imageView.layer.beginTime = timeSincePause;
}
}else{
//暂停旋转,保存当前旋转的进度,在下次开始旋转时使用
CFTimeInterval pausedTime = [self.imageView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
self.imageView.layer.speed = 0.0; ///<停止
self.imageView.layer.timeOffset = pausedTime; ///<保存时间
}
}
完成!