使用过UIImagePickerController的童鞋们都知道,iOS在从相册或者摄像头后选择照片后可以编辑(选择照片的一部分剪切下来),只需要将UIImagePickerController的allowsEditing属性设为YES即可。哇,so easy!
真的如此简单吗?你如果这样想就可以不要继续看下去了。
用过的童鞋应该都会这么认为(至少我是这么认为)系统的那个渣渣真是他妈的弱爆了,主要体现在如下两点:
1、只能裁剪正方形;
2、照片边缘部分可能无法移动到裁剪区域。
哦,怎么办,产品狗就要给他弄一个长方形,甚至裁剪一个不规则形状。
哥前两天就遇到了这么狗血的事情,怎么办?哥百度、谷歌、github都了个遍,好像没找到有什么卵用的东西,于是乎只能自己动手写一个了。
好了,进入正题。如何实现一个可以剪切任意形状的图片编辑器?
需要考虑如下两个问题:
1、用户如何操作,以及界面的实现
2、如何裁剪。
首先解决第一个问题:
系统的图片编辑器是选中框不能移动,可以通过缩放和移动图片,从而确定需要选中的图片区域,此方法的优点是图片可以缩放,小图片可以放大来看清楚。但说真的,我不习惯这种操作。
我采取的方式是,将图片放在确定的位置,通过缩放和移动选中框而确定选中的图片区域。
实现如下:为了实现不规则形状选择时,未选中部分也有半透明阴影,通过在遮挡视图上绘制而成:
遮挡视图.h
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, MGCEditSelectImageViewShapeStyle) {
MGCEditSelectImageViewShapeStyle_rect,
MGCEditSelectImageViewShapeStyle_circle,
};
// 遮挡视图(目前只支持矩形和圆形,其它形状可以类似实现)
@interface MGCEditSelectImageView : UIView
@property (nonatomic, readonly) CGFloat width;
@property (nonatomic, readonly) CGFloat height;
@property (nonatomic, readonly) MGCEditSelectImageViewShapeStyle style;
/**
* 画形状
*
* @param width 宽度、长半径
* @param height 高度、短半径
* @param style 形状类型,当画矩形时,若width或者height中的一个为0,那么画正方形,当画椭圆时,若width或者height为0时,画圆
*/
- (void)drawShapeWithWidth:(CGFloat)width height:(CGFloat)height shapeStyle:(MGCEditSelectImageViewShapeStyle)style;
@end
遮挡视图.m
#import "MGCEditSelectImageView.h"
@interface MGCEditSelectImageView ()
@property (nonatomic, assign) CGFloat width;
@property (nonatomic, assign) CGFloat height;
@property (nonatomic, assign) MGCEditSelectImageViewShapeStyle style;
@end
@implementation MGCEditSelectImageView
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
if (self.superview) {
// 绘制边框,
CGContextAddRect(context, CGRectMake(-self.frame.origin.x - 1, -self.frame.origin.y - 1, self.superview.frame.size.width + 2, self.superview.frame.size.height + 2));
}else{
CGContextAddRect(context, self.bounds);
}
[self drawShapeContext:context];
// 设置触笔颜色
[[UIColor whiteColor] setStroke];
// 将未选中部分蛇者为阴影半透明颜色
[[[UIColor blackColor] colorWithAlphaComponent:0.6] setFill];
CGContextDrawPath(context, kCGPathEOFillStroke);
}
#pragma mark - pravate
// 绘制形状
- (void)drawShapeContext:(CGContextRef)context
{
if (self.width || self.height) {
if (self.width <= 0 && self.height > 0) {
self.width = self.height;
}else if (self.height <= 0 && self.width > 0){
self.height = self.width;
}
CGFloat x = (self.frame.size.width - self.width) / 2;
CGFloat y = (self.frame.size.height - self.height) / 2;
CGRect rect = CGRectMake(x, y, self.width, self.height);
if (self.style == MGCEditSelectImageViewShapeStyle_rect) {
// 绘制矩形
CGContextAddRect(context, rect);
}else if (self.style == MGCEditSelectImageViewShapeStyle_circle){
// 绘制圆形
CGContextAddEllipseInRect(context, rect);
}
}
}
#pragma mark - public
- (void)drawShapeWithWidth:(CGFloat)width height:(CGFloat)height shapeStyle:(MGCEditSelectImageViewShapeStyle)style
{
self.width = width;
self.height = height;
self.style = style;
[self setNeedsDisplay];
}
@end
遮挡视图已经解决,嘿,为什么把选中部分的形状绘制在中心?因为这样的话,在移动选择区域时只需要移动整个遮挡视图,而无需每次都计算绘制形状的位置,为了保证无论如何移动,遮挡视图都会覆盖整个父视图,因此,该遮挡视图的大小必选是父视图大小的9倍。
接下来看控制器代码:
.h
#import <UIKit/UIKit.h>
#import "MGCEditSelectImageView.h"