├── Clip ├── ClipAreaView.h ├── ClipAreaView.m ├── ClipImageView.h ├── ClipImageView.m ├── MidLineView.h └── MidLineView.m ├── ClipImage.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ ├── zhao.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── ClipImage.xcscheme │ │ └── xcschememanagement.plist │ └── zhaosongbo.xcuserdatad │ └── xcschemes │ └── ClipImage.xcscheme ├── ClipImage ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── QRCodeLine.imageset │ │ ├── Contents.json │ │ ├── QRCodeLine@2x.png │ │ └── QRCodeLine@3x.png │ ├── arrow1.imageset │ │ ├── Contents.json │ │ ├── QRCodeTopLeft@2x.png │ │ └── QRCodeTopLeft@3x.png │ ├── arrow2.imageset │ │ ├── Contents.json │ │ ├── QRCodeTopRight@2x.png │ │ └── QRCodeTopRight@3x.png │ ├── arrow3.imageset │ │ ├── Contents.json │ │ ├── QRCodebottomLeft@2x.png │ │ └── QRCodebottomLeft@3x.png │ ├── arrow4.imageset │ │ ├── Contents.json │ │ ├── QRCodebottomRight@2x.png │ │ └── QRCodebottomRight@3x.png │ └── dog.imageset │ │ ├── Contents.json │ │ └── dog.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ClipViewController.h ├── ClipViewController.m ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m ├── ClipRectImage.gif ├── Conclusion └── README.md /Clip/ClipAreaView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClipAreaView.h 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 裁剪区域 8 | 9 | #import 10 | 11 | #define CLIP_WIDTH self.frame.size.width 12 | #define CLIP_HEIGHT self.frame.size.height 13 | 14 | typedef NS_ENUM(NSUInteger, ClipAreaViewType) 15 | { 16 | ClipAreaViewTypeRect = 0, /**< 裁剪区域是矩形*/ 17 | ClipAreaViewTypeArc, /**< 裁剪区域是圆形*/ 18 | }; 19 | 20 | @interface ClipAreaView : UIView 21 | 22 | @property (nonatomic, strong) UIView *clipView; /**< 裁剪区域*/ 23 | @property (nonatomic, assign) ClipAreaViewType clipAreaType; 24 | 25 | /** 26 | * 快速初始化ClipAreaView类 27 | */ 28 | + (instancetype)initWithFrame:(CGRect)frame; 29 | 30 | - (void)resetClipViewFrame; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Clip/ClipAreaView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClipAreaView.m 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 裁剪区域 8 | 9 | #import "ClipAreaView.h" 10 | 11 | @interface ClipAreaView () 12 | 13 | @property (nonatomic, strong) UIPanGestureRecognizer *clipViewPan; 14 | @property (nonatomic, assign) CGPoint originCenter; 15 | 16 | @end 17 | 18 | @implementation ClipAreaView 19 | 20 | #pragma mark -- 初始化 21 | 22 | + (instancetype)initWithFrame:(CGRect)frame 23 | { 24 | return [[self alloc] initWithFrame:frame]; 25 | } 26 | 27 | - (instancetype)initWithFrame:(CGRect)frame 28 | { 29 | if([super initWithFrame:frame]) 30 | { 31 | self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7]; 32 | self.clipAreaType = ClipAreaViewTypeRect; 33 | } 34 | return self; 35 | } 36 | 37 | - (void)layoutSubviews 38 | { 39 | [super layoutSubviews]; 40 | 41 | // 创建裁剪区域 矩形 42 | if(self.clipAreaType == ClipAreaViewTypeRect) 43 | { 44 | [self setupClipView]; 45 | } 46 | else 47 | { 48 | [self addSubview:self.clipView]; 49 | [self resetClipViewFrame]; 50 | } 51 | } 52 | 53 | /** 54 | * 添加点击手势 55 | */ 56 | - (void)setupClipView 57 | { 58 | [self addSubview:self.clipView]; 59 | self.clipViewPan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleCropAreaPan:)]; 60 | [self.clipView addGestureRecognizer:self.clipViewPan]; 61 | } 62 | 63 | /** 64 | * 处理点击手势 重置裁剪区域 65 | */ 66 | - (void)handleCropAreaPan:(UIPanGestureRecognizer *)panGesture 67 | { 68 | if(panGesture.state == UIGestureRecognizerStateBegan) 69 | { 70 | self.originCenter = self.clipView.center; 71 | } 72 | else if(panGesture.state == UIGestureRecognizerStateChanged) 73 | { 74 | CGPoint translation = [panGesture translationInView:self]; 75 | // 将要移动到的位置 76 | CGPoint willCenter = CGPointMake(self.originCenter.x + translation.x, self.originCenter.y + translation.y); 77 | // X方向上最小和最大的移动范围 78 | CGFloat minCenterX = self.clipView.frame.size.width / 2.0; 79 | CGFloat maxCenterX = CLIP_WIDTH - self.clipView.frame.size.width / 2.0; 80 | // Y方向上最小和最大的移动范围 81 | CGFloat minCenterY = self.clipView.frame.size.height / 2.0; 82 | CGFloat maxCenterY = CLIP_HEIGHT - self.clipView.frame.size.height / 2.0; 83 | // 随着手指的移动,重置裁剪区域的位置 84 | self.clipView.center = CGPointMake(MIN(MAX(willCenter.x, minCenterX), maxCenterX), MIN(MAX(willCenter.y, minCenterY), maxCenterY)); 85 | } 86 | } 87 | 88 | /** 89 | * 随着裁剪区域的改变 重置不透明区域,即不裁剪的部分 90 | */ 91 | - (void)resetClipViewFrame 92 | { 93 | UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds]; 94 | UIBezierPath *clearPath = nil; 95 | // 矩形 96 | if(self.clipAreaType == ClipAreaViewTypeRect){ 97 | clearPath = [[UIBezierPath bezierPathWithRect:self.clipView.frame] bezierPathByReversingPath]; 98 | } 99 | else {// 圆形 100 | clearPath = [[UIBezierPath bezierPathWithOvalInRect:self.clipView.frame] bezierPathByReversingPath]; 101 | } 102 | [path appendPath:clearPath]; 103 | CAShapeLayer *shareLayer = (CAShapeLayer *)self.layer.mask; 104 | if(!shareLayer) 105 | { 106 | shareLayer = [CAShapeLayer layer]; 107 | [self.layer setMask:shareLayer]; 108 | } 109 | shareLayer.path = path.CGPath; 110 | } 111 | 112 | - (void)dealloc 113 | { 114 | [self.clipView removeGestureRecognizer:self.clipViewPan]; 115 | } 116 | 117 | #pragma mark -- getter/setter 118 | 119 | - (UIView *)clipView 120 | { 121 | if(!_clipView) 122 | { 123 | _clipView = [[UIView alloc] initWithFrame:CGRectZero]; 124 | _clipView.backgroundColor = [UIColor clearColor]; 125 | } 126 | return _clipView; 127 | } 128 | 129 | 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /Clip/ClipImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClipImageView.h 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 图片裁剪的事件处理、交互 8 | 9 | #import 10 | #import "ClipAreaView.h" 11 | 12 | @interface ClipImageView : UIView 13 | 14 | 15 | @property (nonatomic, strong) UIImage *clipImage; /**< 需要被裁剪的图片*/ 16 | @property (nonatomic, assign) ClipAreaViewType clipType;/**< 裁剪区域的类型*/ 17 | // 若选择是圆形裁剪区域,下面的属性可以不用赋值 18 | @property (nonatomic, strong) UIColor *midLineColor; /**< 中间线颜色*/ 19 | 20 | 21 | 22 | /** 23 | * 快速初始化ClipImageView类 24 | */ 25 | + (instancetype)initWithFrame:(CGRect)frame; 26 | 27 | /** 28 | * 获取裁剪后的图片 29 | */ 30 | - (UIImage *)getClipedImage; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Clip/ClipImageView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClipImageView.m 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 图片裁剪的事件处理、交互 8 | 9 | #import "ClipImageView.h" 10 | #import "MidLineView.h" 11 | 12 | #define CORNER_WIDTH 16 13 | #define CLIP_ARC_DIAMETER 240 14 | 15 | @interface ClipImageView () 16 | 17 | @property (nonatomic, strong) UIImageView *clipImageView; /**< 被裁剪的图片*/ 18 | @property (nonatomic, strong) ClipAreaView *clipAreaView; /**< 裁剪区域*/ 19 | @property (nonatomic, assign) CGFloat clipViewX; /**< 裁剪区域的X*/ 20 | @property (nonatomic, assign) CGFloat clipViewY; /**< 裁剪区域的Y*/ 21 | // 四个拐角 22 | @property (nonatomic, strong) UIImageView *topLeftImageView; 23 | @property (nonatomic, strong) UIImageView *topRightImageView; 24 | @property (nonatomic, strong) UIImageView *bottomLeftImageView; 25 | @property (nonatomic, strong) UIImageView *bottomRightImageView; 26 | // 拐角的手势 27 | @property (nonatomic, strong) UIPanGestureRecognizer *topLeftPan; 28 | @property (nonatomic, strong) UIPanGestureRecognizer *topRightPan; 29 | @property (nonatomic, strong) UIPanGestureRecognizer *bottomLeftPan; 30 | @property (nonatomic, strong) UIPanGestureRecognizer *bottomRightPan; 31 | // 四个拐角的坐标 32 | @property (nonatomic, assign) CGPoint topLeftPoint; 33 | @property (nonatomic, assign) CGPoint topRightPoint; 34 | @property (nonatomic, assign) CGPoint bottomLeftPoint; 35 | @property (nonatomic, assign) CGPoint bottomRightPoint; 36 | //四条中间线 37 | @property (nonatomic, strong) MidLineView *topMidLine; 38 | @property (nonatomic, strong) MidLineView *leftMidLine; 39 | @property (nonatomic, strong) MidLineView *bottomMidLine; 40 | @property (nonatomic, strong) MidLineView *rightMidLine; 41 | 42 | @property (nonatomic, assign) CGFloat lastDistance; /**< 先前两个手指的距离*/ 43 | @property (nonatomic, assign) CGPoint imageStartMoveCenter; /**< 开始移动手指时图片的center*/ 44 | @property (nonatomic, assign) CGPoint startTouchPoint; /**< 开始移动手指point*/ 45 | 46 | @end 47 | 48 | @implementation ClipImageView 49 | 50 | #pragma mark -- 初始化 51 | 52 | + (instancetype)initWithFrame:(CGRect)frame 53 | { 54 | return [[self alloc] initWithFrame:frame]; 55 | } 56 | 57 | - (instancetype)initWithFrame:(CGRect)frame 58 | { 59 | if([super initWithFrame:frame]) 60 | { 61 | self.clipViewX = (MAX(CLIP_WIDTH, CLIP_HEIGHT) - MIN(CLIP_WIDTH, CLIP_HEIGHT)) / 2.0; 62 | self.clipViewY = self.clipViewX; 63 | } 64 | return self; 65 | } 66 | 67 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 68 | { 69 | if([super initWithCoder:aDecoder]) 70 | { 71 | self.clipViewX = (MAX(CLIP_WIDTH, CLIP_HEIGHT) - MIN(CLIP_WIDTH, CLIP_HEIGHT)) / 2.0; 72 | self.clipViewY = self.clipViewX; 73 | } 74 | return self; 75 | } 76 | 77 | - (void)layoutSubviews 78 | { 79 | [super layoutSubviews]; 80 | [self addSubview:self.clipImageView]; 81 | [self addSubview:self.clipAreaView]; 82 | 83 | if(self.clipType == ClipAreaViewTypeRect) 84 | { 85 | [self.clipAreaView addObserver:self forKeyPath:@"clipView.frame" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil]; 86 | [self.clipAreaView addObserver:self forKeyPath:@"clipView.center" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil]; 87 | // 设置裁剪区域的四个拐角 88 | [self setupCornerImageView]; 89 | // 根据四个拐角的位置确定裁剪区域(透明区域) 90 | [self resetClipViewFrameWhenCornerFrameSure]; 91 | // 创建中间线 92 | [self setupMidLine]; 93 | } 94 | else 95 | { 96 | // 圆形裁剪区域最大直径240 97 | CGFloat w = MIN(CLIP_WIDTH, CLIP_HEIGHT) < CLIP_ARC_DIAMETER ?:CLIP_ARC_DIAMETER; 98 | CGFloat x = (CLIP_WIDTH - w) / 2; 99 | CGFloat y = (CLIP_HEIGHT - w) / 2; 100 | self.clipAreaView.clipView.frame = CGRectMake(x, y, w, w); 101 | } 102 | } 103 | 104 | #pragma mark -- KVO 105 | 106 | // KVO监测裁剪区域frame或center的改变 107 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 108 | { 109 | // 随着点击手势的移动,改变裁剪区域的frame 110 | [self.clipAreaView resetClipViewFrame]; 111 | // 随着裁剪区域的移动,改变四个拐角图片的位置 112 | [self resetCornerViewFrameWhenClipViewMoving]; 113 | // 随着裁剪区域的移动,改变中间线的位置 114 | [self resetMidLineViewFrameWhenClipViewMoving]; 115 | } 116 | 117 | #pragma mark -- 裁剪区域 118 | 119 | /** 120 | * 根据四个拐角的位置 重新确定裁剪区域(透明区域) 121 | */ 122 | - (void)resetClipViewFrameWhenCornerFrameSure 123 | { 124 | self.clipAreaView.clipView.frame = CGRectMake(self.topLeftImageView.frame.origin.x, self.topLeftImageView.frame.origin.y, CGRectGetMaxX(self.topRightImageView.frame) - CGRectGetMinX(self.topLeftImageView.frame), CGRectGetMaxY(self.bottomLeftImageView.frame) - CGRectGetMinY(self.topLeftImageView.frame)); 125 | } 126 | 127 | #pragma mark -- 四个拐角 128 | /** 129 | * 设置裁剪区域的四个拐角的图片 添加手势 130 | */ 131 | - (void)setupCornerImageView 132 | { 133 | // 刚出现的裁剪区域是一个正方形 134 | if(CLIP_WIDTH >= CLIP_HEIGHT) 135 | { 136 | self.topLeftImageView.frame = CGRectMake(self.clipViewX, 0, CORNER_WIDTH, CORNER_WIDTH); 137 | self.topRightImageView.frame = CGRectMake(CLIP_WIDTH - self.clipViewX - CORNER_WIDTH, 0, CORNER_WIDTH, CORNER_WIDTH); 138 | self.bottomLeftImageView.frame = CGRectMake(self.clipViewX, CLIP_HEIGHT - CORNER_WIDTH, CORNER_WIDTH, CORNER_WIDTH); 139 | self.bottomRightImageView.frame = CGRectMake(CLIP_WIDTH - self.clipViewX - CORNER_WIDTH, CLIP_HEIGHT - CORNER_WIDTH, CORNER_WIDTH, CORNER_WIDTH); 140 | } 141 | else 142 | { 143 | self.topLeftImageView.frame = CGRectMake(0, self.clipViewY, CORNER_WIDTH, CORNER_WIDTH); 144 | self.topRightImageView.frame = CGRectMake(CLIP_WIDTH - CORNER_WIDTH, self.clipViewY, CORNER_WIDTH, CORNER_WIDTH); 145 | self.bottomLeftImageView.frame = CGRectMake(0, CLIP_HEIGHT-self.clipViewX-CORNER_WIDTH, CORNER_WIDTH, CORNER_WIDTH); 146 | self.bottomRightImageView.frame = CGRectMake(CLIP_WIDTH - CORNER_WIDTH, CLIP_HEIGHT-self.clipViewX-CORNER_WIDTH, CORNER_WIDTH, CORNER_WIDTH); 147 | } 148 | 149 | [self addSubview:self.topLeftImageView]; 150 | [self addSubview:self.topRightImageView]; 151 | [self addSubview:self.bottomLeftImageView]; 152 | [self addSubview:self.bottomRightImageView]; 153 | } 154 | 155 | /** 156 | * 处理拐角的点击手势,使裁剪区域能够随着某个corner的移动而变化 157 | */ 158 | - (void)handleCornerPan:(UIPanGestureRecognizer *)panGesture 159 | { 160 | // 响应的imageView 161 | UIImageView *imageView = (UIImageView *)panGesture.view; 162 | // 移动的坐标 163 | CGPoint movePoint = [panGesture translationInView:self]; 164 | 165 | if(panGesture.state == UIGestureRecognizerStateBegan) 166 | { 167 | // 裁剪区域四个拐角的坐标 168 | self.topLeftPoint = self.clipAreaView.clipView.frame.origin; 169 | self.topRightPoint = CGPointMake(CGRectGetMaxX(self.clipAreaView.clipView.frame), CGRectGetMinY(self.clipAreaView.clipView.frame)); 170 | self.bottomLeftPoint = CGPointMake(CGRectGetMinX(self.clipAreaView.clipView.frame), CGRectGetMaxY(self.clipAreaView.clipView.frame)); 171 | self.bottomRightPoint = CGPointMake(CGRectGetMaxX(self.clipAreaView.clipView.frame), CGRectGetMaxY(self.clipAreaView.clipView.frame)); 172 | } 173 | else if(panGesture.state == UIGestureRecognizerStateChanged) 174 | { 175 | // 点击不同corner,改变裁剪区域的frame,从而通过KVO改变Corner的frame 176 | if([imageView isEqual:self.topLeftImageView]) 177 | { 178 | // 将要移动到的位置 179 | CGPoint willPoint = CGPointMake(self.topLeftPoint.x + movePoint.x, self.topLeftPoint.y + movePoint.y); 180 | // 实际能能到达的范围 181 | CGPoint actualPoint = CGPointMake(MIN(MAX(0, willPoint.x), CGRectGetMinX(self.topRightImageView.frame) - CORNER_WIDTH - MID_LINE_WIDTH), MIN(MAX(0, willPoint.y), CGRectGetMinY(self.bottomLeftImageView.frame) - CORNER_WIDTH - MID_LINE_WIDTH)); 182 | // 确定变化后的frame 183 | self.clipAreaView.clipView.frame = CGRectMake(actualPoint.x, actualPoint.y, CGRectGetMaxX(self.topRightImageView.frame) - actualPoint.x, CGRectGetMaxY(self.bottomLeftImageView.frame) - actualPoint.y); 184 | } 185 | else if([imageView isEqual:self.topRightImageView]) 186 | { 187 | CGPoint willPoint = CGPointMake(self.topRightPoint.x + movePoint.x, self.topRightPoint.y + movePoint.y); 188 | 189 | CGPoint actualPoint = CGPointMake(MIN(MAX(self.topLeftPoint.x + CORNER_WIDTH*2 + MID_LINE_WIDTH, willPoint.x), CLIP_WIDTH), MIN(MAX(0, willPoint.y), CGRectGetMaxY(self.bottomLeftImageView.frame) - CORNER_WIDTH*2 - MID_LINE_WIDTH)); 190 | 191 | self.clipAreaView.clipView.frame = CGRectMake(self.topLeftPoint.x, actualPoint.y, actualPoint.x - self.topLeftPoint.x, CGRectGetMaxY(self.bottomLeftImageView.frame) - actualPoint.y); 192 | } 193 | else if([imageView isEqual:self.bottomLeftImageView]) 194 | { 195 | CGPoint willPoint = CGPointMake(self.bottomLeftPoint.x + movePoint.x, self.bottomLeftPoint.y + movePoint.y); 196 | 197 | CGPoint actualPoint = CGPointMake(MIN(MAX(0, willPoint.x), CGRectGetMaxX(self.topRightImageView.frame) - CORNER_WIDTH*2 - MID_LINE_WIDTH), MIN(MAX(self.topLeftPoint.y + CORNER_WIDTH*2 + MID_LINE_WIDTH, willPoint.y), CLIP_HEIGHT)); 198 | 199 | self.clipAreaView.clipView.frame = CGRectMake(actualPoint.x, self.topLeftPoint.y, CGRectGetMaxX(self.topRightImageView.frame) - actualPoint.x, actualPoint.y - self.topLeftPoint.y); 200 | } 201 | else 202 | { 203 | CGPoint willPoint = CGPointMake(self.bottomRightPoint.x + movePoint.x, self.bottomRightPoint.y + movePoint.y); 204 | 205 | CGPoint actualPoint = CGPointMake(MIN(MAX(self.topLeftPoint.x + CORNER_WIDTH*2 + MID_LINE_WIDTH, willPoint.x), CLIP_WIDTH), MIN(MAX(self.topLeftPoint.y + CORNER_WIDTH*2 + MID_LINE_WIDTH, willPoint.y), CLIP_HEIGHT)); 206 | 207 | self.clipAreaView.clipView.frame = CGRectMake(self.topLeftPoint.x, self.topLeftPoint.y, actualPoint.x - self.topLeftPoint.x, actualPoint.y - self.topLeftPoint.y); 208 | } 209 | } 210 | } 211 | 212 | /** 213 | * 随着裁剪区域的移动,改变四个拐角图片的位置 214 | */ 215 | - (void)resetCornerViewFrameWhenClipViewMoving 216 | { 217 | self.topLeftImageView.frame = CGRectMake(CGRectGetMinX(self.clipAreaView.clipView.frame), CGRectGetMinY(self.clipAreaView.clipView.frame), CORNER_WIDTH, CORNER_WIDTH); 218 | self.topRightImageView.frame = CGRectMake(CGRectGetMaxX(self.clipAreaView.clipView.frame) - CORNER_WIDTH, CGRectGetMinY(self.clipAreaView.clipView.frame), CORNER_WIDTH, CORNER_WIDTH); 219 | self.bottomLeftImageView.frame = CGRectMake(CGRectGetMinX(self.clipAreaView.clipView.frame), CGRectGetMaxY(self.clipAreaView.clipView.frame) - CORNER_WIDTH, CORNER_WIDTH, CORNER_WIDTH); 220 | self.bottomRightImageView.frame = CGRectMake(CGRectGetMaxX(self.clipAreaView.clipView.frame) - CORNER_WIDTH, CGRectGetMaxY(self.clipAreaView.clipView.frame) - CORNER_WIDTH, CORNER_WIDTH, CORNER_WIDTH); 221 | } 222 | 223 | #pragma mark -- 中间点击手势线 224 | 225 | /** 226 | * 创建中间点击手势线 227 | */ 228 | - (void)setupMidLine 229 | { 230 | [self addSubview:self.topMidLine]; 231 | [self addSubview:self.leftMidLine]; 232 | [self addSubview:self.bottomMidLine]; 233 | [self addSubview:self.rightMidLine]; 234 | } 235 | 236 | - (void)handleMidLinePan:(UIPanGestureRecognizer *)panGesture 237 | { 238 | MidLineView *midLine = (MidLineView *)panGesture.view; 239 | CGPoint movePoint = [panGesture translationInView:self]; 240 | 241 | if(panGesture.state == UIGestureRecognizerStateBegan) 242 | { 243 | self.topLeftPoint = self.clipAreaView.clipView.frame.origin; 244 | self.bottomRightPoint = CGPointMake(CGRectGetMaxX(self.clipAreaView.clipView.frame), CGRectGetMaxY(self.clipAreaView.clipView.frame)); 245 | } 246 | else if(panGesture.state == UIGestureRecognizerStateChanged) 247 | { 248 | switch (midLine.midLineType) 249 | { 250 | case MidLineViewTypeTop: 251 | { 252 | CGFloat actualY = MIN(MAX(0, self.topLeftPoint.y + movePoint.y), CGRectGetMaxY(self.clipAreaView.clipView.frame) - CORNER_WIDTH*2 - MID_LINE_WIDTH); 253 | self.clipAreaView.clipView.frame = CGRectMake(self.topLeftPoint.x, actualY, CGRectGetWidth(self.clipAreaView.clipView.frame), CGRectGetMaxY(self.clipAreaView.clipView.frame) - actualY); 254 | break; 255 | } 256 | case MidLineViewTypeLeft: 257 | { 258 | CGFloat actualX = MIN(MAX(0, self.topLeftPoint.x + movePoint.x), CGRectGetMaxX(self.clipAreaView.clipView.frame) - CORNER_WIDTH*2 - MID_LINE_WIDTH); 259 | self.clipAreaView.clipView.frame = CGRectMake(actualX, self.topLeftPoint.y, CGRectGetMaxX(self.clipAreaView.clipView.frame) - actualX, CGRectGetHeight(self.clipAreaView.clipView.frame)); 260 | break; 261 | } 262 | case MidLineViewTypeBottom: 263 | { 264 | CGFloat actualY = MIN(MAX(self.topLeftPoint.y + CORNER_WIDTH*2 + MID_LINE_WIDTH, self.bottomRightPoint.y + movePoint.y), CLIP_HEIGHT); 265 | self.clipAreaView.clipView.frame = CGRectMake(self.topLeftPoint.x, self.topLeftPoint.y, CGRectGetWidth(self.clipAreaView.clipView.frame), actualY - self.topLeftPoint.y); 266 | break; 267 | } 268 | case MidLineViewTypeRight: 269 | { 270 | CGFloat actualX = MIN(MAX(self.topLeftPoint.x + CORNER_WIDTH*2 + MID_LINE_WIDTH, self.bottomRightPoint.x + movePoint.x), CLIP_WIDTH); 271 | self.clipAreaView.clipView.frame = CGRectMake(self.topLeftPoint.x, self.topLeftPoint.y,actualX - self.topLeftPoint.x, CGRectGetHeight(self.clipAreaView.clipView.frame)); 272 | break; 273 | } 274 | } 275 | } 276 | } 277 | 278 | /** 279 | * 重置中间线的位置 280 | */ 281 | - (void)resetMidLineViewFrameWhenClipViewMoving 282 | { 283 | self.topMidLine.center = CGPointMake(CGRectGetMidX(self.clipAreaView.clipView.frame), CGRectGetMinY(self.clipAreaView.clipView.frame)); 284 | self.leftMidLine.center = CGPointMake(CGRectGetMinX(self.clipAreaView.clipView.frame), CGRectGetMidY(self.clipAreaView.clipView.frame)); 285 | self.bottomMidLine.center = CGPointMake(CGRectGetMidX(self.clipAreaView.clipView.frame), CGRectGetMaxY(self.clipAreaView.clipView.frame)); 286 | self.rightMidLine.center = CGPointMake(CGRectGetMaxX(self.clipAreaView.clipView.frame), CGRectGetMidY(self.clipAreaView.clipView.frame)); 287 | } 288 | 289 | #pragma mark -- 缩放裁剪区域 290 | 291 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 292 | { 293 | NSSet *allTouchs = [event allTouches]; 294 | if(allTouchs.count == 1 && self.clipType == ClipAreaViewTypeArc) // 一个手指移动图片 295 | { 296 | self.imageStartMoveCenter = self.clipImageView.center; 297 | self.startTouchPoint = [[touches anyObject] locationInView:self]; 298 | } 299 | } 300 | 301 | // 移动手指 302 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 303 | { 304 | NSSet *allTouchs = [event allTouches]; 305 | if(allTouchs.count == 1 && self.clipType == ClipAreaViewTypeArc) // 一个手指移动图片 306 | { 307 | CGPoint movePoint = [[touches anyObject] locationInView:self]; 308 | // 手指移动的距离 309 | CGFloat x = movePoint.x - self.startTouchPoint.x; 310 | CGFloat y = movePoint.y - self.startTouchPoint.y; 311 | 312 | CGPoint willMoveToPoint = CGPointMake(self.imageStartMoveCenter.x + x, self.imageStartMoveCenter.y + y); 313 | self.clipImageView.center = willMoveToPoint; 314 | } 315 | else if(allTouchs.count == 2) // 两个手指缩放 316 | { 317 | if(self.clipType == ClipAreaViewTypeRect) 318 | { 319 | [self scaleClipView:self.clipAreaView.clipView withTouches:[allTouchs allObjects]]; 320 | } 321 | else 322 | { 323 | [self scaleClipView:self.clipImageView withTouches:[allTouchs allObjects]]; 324 | } 325 | } 326 | } 327 | 328 | // 手指移动结束 329 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 330 | { 331 | if(self.clipType == ClipAreaViewTypeArc) 332 | { 333 | [self correctClipImageViewFrame]; 334 | } 335 | } 336 | 337 | /** 338 | * 根据两个手指的变化,缩放裁剪区域 或缩放被裁剪的图片 339 | */ 340 | - (void)scaleClipView:(UIView *)view withTouches:(NSArray *)touches 341 | { 342 | CGPoint touch1 = [touches[0] locationInView:self]; 343 | CGPoint touch2 = [touches[1] locationInView:self]; 344 | 345 | // 计算两个手指的距离 346 | CGFloat distance = sqrtf((touch1.x - touch2.x)*(touch1.x - touch2.x) + (touch1.y - touch2.y)*(touch1.y - touch2.y)); 347 | // 缩放裁剪区域,宽高最小为100 348 | CGRect viewFrame = view.frame; 349 | 350 | // 两指距离增加 即裁剪区域或图片放大 351 | if(distance > self.lastDistance + 1) 352 | { 353 | viewFrame.size.width += 8; 354 | self.lastDistance = distance; 355 | } 356 | // 两指距离缩小 即裁剪区域或图片缩小 357 | else if(distance < self.lastDistance - 1) 358 | { 359 | viewFrame.size.width -= 8; 360 | self.lastDistance = distance; 361 | } 362 | // 等比例缩放 换算出高度要变化的距离 363 | viewFrame.size.height = viewFrame.size.width * CGRectGetHeight(view.frame) / CGRectGetWidth(view.frame); 364 | 365 | // 算出x,y变化的距离 366 | CGFloat scaleX = (viewFrame.size.width - CGRectGetWidth(view.frame)) / 2.0; 367 | CGFloat scaleY = (viewFrame.size.height - CGRectGetHeight(view.frame)) / 2.0; 368 | 369 | CGFloat actualX = viewFrame.origin.x - scaleX; 370 | CGFloat actualY = viewFrame.origin.y - scaleY; 371 | 372 | if(self.clipType == ClipAreaViewTypeRect) 373 | { 374 | // 限定x,y,W,H 375 | if(actualX < 0 || actualY < 0) return; 376 | // 最大W,H 377 | if(viewFrame.size.width + actualX > CLIP_WIDTH || viewFrame.size.height + actualY > CLIP_HEIGHT) return; 378 | // 最小W,H 379 | if(viewFrame.size.width <= 100 || viewFrame.size.height <= 100) return; 380 | // 改变裁剪区域的frame 381 | view.frame = CGRectMake(actualX, actualY, viewFrame.size.width, viewFrame.size.height); 382 | } 383 | else 384 | { 385 | // 改变图片的frame 386 | view.frame = CGRectMake(actualX, actualY, viewFrame.size.width, viewFrame.size.height); 387 | } 388 | } 389 | 390 | /** 391 | * 一个手指移动结束后,重置被裁剪图片的frame 392 | */ 393 | - (void)correctClipImageViewFrame 394 | { 395 | CGFloat clipImageX = CGRectGetMinX(self.clipImageView.frame); 396 | CGFloat clipImageY = CGRectGetMinY(self.clipImageView.frame); 397 | CGFloat clipImageW = CGRectGetWidth(self.clipImageView.frame); 398 | CGFloat clipImageH = CGRectGetHeight(self.clipImageView.frame); 399 | 400 | // 图片的X值最大不能超过裁剪区域的X值 最小不能小于.. 401 | CGFloat actualX = MIN(MAX(CGRectGetMaxX(self.clipAreaView.clipView.frame) - clipImageW, clipImageX), CGRectGetMinX(self.clipAreaView.clipView.frame)); 402 | // 图片的Y值最大不能超过裁剪区域的Y值 最小不能小于.. 403 | CGFloat actualY = MIN(MAX(CGRectGetMaxY(self.clipAreaView.clipView.frame) - clipImageH, clipImageY), CGRectGetMinY(self.clipAreaView.clipView.frame)); 404 | 405 | // 图片的宽高最大为自身宽高的1.5 最小为裁剪区域的直径+10 406 | CGFloat actualW = MIN(MAX(CLIP_ARC_DIAMETER + 10, clipImageW), self.clipImage.size.width * 1.5); 407 | CGFloat actualH = MIN(MAX(CLIP_ARC_DIAMETER + 10, clipImageH), self.clipImage.size.height * 1.5); 408 | 409 | self.clipImageView.frame = CGRectMake(actualX, actualY, actualW, actualH); 410 | } 411 | 412 | #pragma mark -- 裁剪 413 | 414 | - (UIImage *)getClipedImage 415 | { 416 | if(self.clipType == ClipAreaViewTypeRect) 417 | { 418 | return [self clipImageWithRectangle]; // 矩形裁剪框 419 | } 420 | else // 圆形裁剪框 421 | { 422 | UIImage *subImage = [self clipImageWithRectangle]; 423 | // 将裁剪出来的矩形修改成圆形 424 | CGFloat radius = MIN(subImage.size.width, subImage.size.height) / 2.0; 425 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(subImage.size.width, subImage.size.height), NO, 0); 426 | UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(subImage.size.width/2, subImage.size.height/2) radius:radius startAngle:0 endAngle:2*M_PI clockwise:0]; 427 | [path addClip]; 428 | [subImage drawAtPoint:CGPointZero]; 429 | UIImage *clipImage = UIGraphicsGetImageFromCurrentImageContext(); 430 | UIGraphicsEndImageContext(); 431 | return clipImage; 432 | } 433 | } 434 | 435 | - (UIImage *)clipImageWithRectangle 436 | { 437 | // 裁剪框是矩形时,self.clipAreaView与self.clipImageView的frame一样 所以转换坐标相当于没变 438 | // 裁剪框是圆形时,由于图片可以缩放,必须重新计算裁剪框的frame,主要是重算x,y 439 | CGRect convertFrame = [self.clipAreaView convertRect:self.clipAreaView.clipView.frame toView:self.clipImageView]; 440 | 441 | //imageView的size可能和iamge的size不一样,而裁剪是按image的size算,这里必须换算 442 | CGFloat scaleW = self.clipImage.size.width / self.clipImageView.frame.size.width; 443 | CGFloat scaleH = self.clipImage.size.height / self.clipImageView.frame.size.height; 444 | // 实际需要裁剪的frame 445 | CGRect frame = CGRectMake(convertFrame.origin.x * scaleW, convertFrame.origin.y * scaleH, convertFrame.size.width * scaleW, convertFrame.size.height * scaleH); 446 | 447 | //NSLog(@"%@ %@", NSStringFromCGRect(self.clipImageView.frame), NSStringFromCGRect(self.clipAreaView.clipView.frame)); 448 | // 这个方法所截出来的图是按原有图片的size算,不是你给出的imageView的size算 449 | CGImageRef imageRef = CGImageCreateWithImageInRect(self.clipImageView.image.CGImage, frame); 450 | UIImage *subImage = [UIImage imageWithCGImage:imageRef]; 451 | CGImageRelease(imageRef); 452 | //NSLog(@"%@", NSStringFromCGSize(subImage.size)); 453 | return subImage; 454 | } 455 | 456 | - (void)dealloc 457 | { 458 | if(self.clipType == ClipAreaViewTypeRect) 459 | { 460 | [self.clipAreaView removeObserver:self forKeyPath:@"clipView.frame"]; 461 | [self.clipAreaView removeObserver:self forKeyPath:@"clipView.center"]; 462 | 463 | [self.topLeftImageView removeGestureRecognizer:self.topLeftPan]; 464 | [self.topRightImageView removeGestureRecognizer:self.topRightPan]; 465 | [self.bottomLeftImageView removeGestureRecognizer:self.bottomLeftPan]; 466 | [self.topRightImageView removeGestureRecognizer:self.bottomRightPan]; 467 | } 468 | } 469 | 470 | #pragma mark -- getter/setter 471 | 472 | - (UIImageView *)clipImageView 473 | { 474 | if(!_clipImageView) 475 | { 476 | _clipImageView = [[UIImageView alloc] initWithFrame:self.bounds]; 477 | _clipImageView.image = self.clipImage; 478 | } 479 | return _clipImageView; 480 | } 481 | 482 | - (ClipAreaView *)clipAreaView 483 | { 484 | if(!_clipAreaView) 485 | { 486 | _clipAreaView = [[ClipAreaView alloc] initWithFrame:self.bounds]; 487 | _clipAreaView.clipAreaType = self.clipType; 488 | } 489 | return _clipAreaView; 490 | } 491 | 492 | - (UIImageView *)topLeftImageView 493 | { 494 | if(!_topLeftImageView) 495 | { 496 | _topLeftImageView = [[UIImageView alloc] init]; 497 | _topLeftImageView.userInteractionEnabled = YES; 498 | _topLeftImageView.image = [UIImage imageNamed:@"arrow1"]; 499 | [_topLeftImageView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleCornerPan:)]]; 500 | } 501 | return _topLeftImageView; 502 | } 503 | 504 | - (UIImageView *)topRightImageView 505 | { 506 | if(!_topRightImageView) 507 | { 508 | _topRightImageView = [[UIImageView alloc] init]; 509 | _topRightImageView.userInteractionEnabled = YES; 510 | _topRightImageView.image = [UIImage imageNamed:@"arrow2"]; 511 | [_topRightImageView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleCornerPan:)]]; 512 | } 513 | return _topRightImageView; 514 | } 515 | 516 | - (UIImageView *)bottomLeftImageView 517 | { 518 | if(!_bottomLeftImageView) 519 | { 520 | _bottomLeftImageView = [[UIImageView alloc] init]; 521 | _bottomLeftImageView.userInteractionEnabled = YES; 522 | _bottomLeftImageView.image = [UIImage imageNamed:@"arrow3"]; 523 | [_bottomLeftImageView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleCornerPan:)]]; 524 | } 525 | return _bottomLeftImageView; 526 | } 527 | 528 | - (UIImageView *)bottomRightImageView 529 | { 530 | if(!_bottomRightImageView) 531 | { 532 | _bottomRightImageView = [[UIImageView alloc] init]; 533 | _bottomRightImageView.userInteractionEnabled = YES; 534 | _bottomRightImageView.image = [UIImage imageNamed:@"arrow4"]; 535 | [_bottomRightImageView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleCornerPan:)]]; 536 | } 537 | return _bottomRightImageView; 538 | } 539 | 540 | - (MidLineView *)topMidLine 541 | { 542 | if(!_topMidLine) 543 | { 544 | _topMidLine = [[MidLineView alloc] initWithWidth:MID_LINE_WIDTH height:MID_LINE_INVISIBLE type:MidLineViewTypeTop]; 545 | _topMidLine.midLineColor = self.midLineColor; 546 | [_topMidLine addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMidLinePan:)]]; 547 | } 548 | return _topMidLine; 549 | } 550 | 551 | - (MidLineView *)leftMidLine 552 | { 553 | if(!_leftMidLine) 554 | { 555 | _leftMidLine = [[MidLineView alloc] initWithWidth:MID_LINE_INVISIBLE height:MID_LINE_WIDTH type:MidLineViewTypeLeft]; 556 | _leftMidLine.midLineColor = self.midLineColor; 557 | 558 | [_leftMidLine addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMidLinePan:)]]; 559 | } 560 | return _leftMidLine; 561 | } 562 | 563 | - (MidLineView *)bottomMidLine 564 | { 565 | if(!_bottomMidLine) 566 | { 567 | _bottomMidLine = [[MidLineView alloc] initWithWidth:MID_LINE_WIDTH height:MID_LINE_INVISIBLE type:MidLineViewTypeBottom]; 568 | _bottomMidLine.midLineColor = self.midLineColor; 569 | 570 | [_bottomMidLine addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMidLinePan:)]]; 571 | } 572 | return _bottomMidLine; 573 | } 574 | 575 | - (MidLineView *)rightMidLine 576 | { 577 | if(!_rightMidLine) 578 | { 579 | _rightMidLine = [[MidLineView alloc] initWithWidth:MID_LINE_INVISIBLE height:MID_LINE_WIDTH type:MidLineViewTypeRight]; 580 | _rightMidLine.midLineColor = self.midLineColor; 581 | 582 | [_rightMidLine addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMidLinePan:)]]; 583 | } 584 | return _rightMidLine; 585 | } 586 | 587 | @end 588 | -------------------------------------------------------------------------------- /Clip/MidLineView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MidLineView.h 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/4. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 中间线 8 | 9 | #import 10 | 11 | #define MID_LINE_WIDTH 30 12 | #define MID_LINE_HEIGHT 5 13 | #define MID_LINE_INVISIBLE 25 14 | 15 | typedef NS_ENUM(NSInteger, MidLineViewType) 16 | { 17 | MidLineViewTypeTop = 0, 18 | MidLineViewTypeLeft, 19 | MidLineViewTypeBottom, 20 | MidLineViewTypeRight, 21 | }; 22 | 23 | @interface MidLineView : UIView 24 | 25 | @property (nonatomic, assign) CGFloat midLineWidth; /**< 能看到的宽度*/ 26 | @property (nonatomic, assign) CGFloat midLineHeight; /**< 能看到的高度*/ 27 | @property (nonatomic, assign) MidLineViewType midLineType; 28 | @property (nonatomic, strong) UIColor *midLineColor; 29 | 30 | - (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)heigth type:(MidLineViewType)type; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Clip/MidLineView.m: -------------------------------------------------------------------------------- 1 | // 2 | // MidLineView.m 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/4. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 中间线 8 | 9 | #import "MidLineView.h" 10 | 11 | @implementation MidLineView 12 | 13 | - (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)heigth type:(MidLineViewType)type 14 | { 15 | if([super init]) 16 | { 17 | self.frame = CGRectMake(0, 0, width, heigth); 18 | self.backgroundColor = [UIColor clearColor]; 19 | self.midLineWidth = width; 20 | self.midLineHeight = heigth; 21 | self.midLineType = type; 22 | } 23 | return self; 24 | } 25 | 26 | - (void)drawRect:(CGRect)rect 27 | { 28 | CGContextRef context = UIGraphicsGetCurrentContext(); 29 | 30 | [self.midLineColor setStroke]; 31 | CGContextSetLineWidth(context, MID_LINE_HEIGHT); 32 | 33 | switch (self.midLineType) 34 | { 35 | case MidLineViewTypeTop: 36 | case MidLineViewTypeBottom: 37 | { 38 | CGContextMoveToPoint(context, 0, self.midLineHeight/2.0); 39 | CGContextAddLineToPoint(context, self.midLineWidth, self.midLineHeight/2.0); 40 | break; 41 | } 42 | 43 | case MidLineViewTypeLeft: 44 | case MidLineViewTypeRight: 45 | { 46 | CGContextMoveToPoint(context, self.midLineWidth/2.0, 0); 47 | CGContextAddLineToPoint(context, self.midLineWidth/2.0, self.midLineHeight); 48 | break; 49 | } 50 | } 51 | CGContextStrokePath(context); 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /ClipImage.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FEEF2C0B1DD44DD80080EFBC /* Conclusion in Resources */ = {isa = PBXBuildFile; fileRef = FEEF2C0A1DD44DD80080EFBC /* Conclusion */; }; 11 | FEF757F01DC82C510070F0C5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FEF757EF1DC82C510070F0C5 /* main.m */; }; 12 | FEF757F31DC82C510070F0C5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FEF757F21DC82C510070F0C5 /* AppDelegate.m */; }; 13 | FEF757F61DC82C510070F0C5 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FEF757F51DC82C510070F0C5 /* ViewController.m */; }; 14 | FEF757F91DC82C510070F0C5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FEF757F71DC82C510070F0C5 /* Main.storyboard */; }; 15 | FEF757FB1DC82C510070F0C5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FEF757FA1DC82C510070F0C5 /* Assets.xcassets */; }; 16 | FEF757FE1DC82C510070F0C5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FEF757FC1DC82C510070F0C5 /* LaunchScreen.storyboard */; }; 17 | FEF758081DC82CD90070F0C5 /* ClipImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = FEF758071DC82CD90070F0C5 /* ClipImageView.m */; }; 18 | FEF7580B1DC834CB0070F0C5 /* ClipViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FEF7580A1DC834CB0070F0C5 /* ClipViewController.m */; }; 19 | FEF7580E1DC847500070F0C5 /* ClipAreaView.m in Sources */ = {isa = PBXBuildFile; fileRef = FEF7580D1DC847500070F0C5 /* ClipAreaView.m */; }; 20 | FEF758111DCC2CA60070F0C5 /* MidLineView.m in Sources */ = {isa = PBXBuildFile; fileRef = FEF758101DCC2CA60070F0C5 /* MidLineView.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | FEEF2C0A1DD44DD80080EFBC /* Conclusion */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Conclusion; sourceTree = ""; }; 25 | FEF757EB1DC82C500070F0C5 /* ClipImage.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ClipImage.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | FEF757EF1DC82C510070F0C5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 27 | FEF757F11DC82C510070F0C5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 28 | FEF757F21DC82C510070F0C5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 29 | FEF757F41DC82C510070F0C5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 30 | FEF757F51DC82C510070F0C5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 31 | FEF757F81DC82C510070F0C5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 32 | FEF757FA1DC82C510070F0C5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 33 | FEF757FD1DC82C510070F0C5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 34 | FEF757FF1DC82C510070F0C5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | FEF758061DC82CD90070F0C5 /* ClipImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClipImageView.h; sourceTree = ""; }; 36 | FEF758071DC82CD90070F0C5 /* ClipImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ClipImageView.m; sourceTree = ""; }; 37 | FEF758091DC834CB0070F0C5 /* ClipViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClipViewController.h; sourceTree = ""; }; 38 | FEF7580A1DC834CB0070F0C5 /* ClipViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ClipViewController.m; sourceTree = ""; }; 39 | FEF7580C1DC847500070F0C5 /* ClipAreaView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClipAreaView.h; sourceTree = ""; }; 40 | FEF7580D1DC847500070F0C5 /* ClipAreaView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ClipAreaView.m; sourceTree = ""; }; 41 | FEF7580F1DCC2CA60070F0C5 /* MidLineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MidLineView.h; sourceTree = ""; }; 42 | FEF758101DCC2CA60070F0C5 /* MidLineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MidLineView.m; sourceTree = ""; }; 43 | /* End PBXFileReference section */ 44 | 45 | /* Begin PBXFrameworksBuildPhase section */ 46 | FEF757E81DC82C500070F0C5 /* Frameworks */ = { 47 | isa = PBXFrameworksBuildPhase; 48 | buildActionMask = 2147483647; 49 | files = ( 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXFrameworksBuildPhase section */ 54 | 55 | /* Begin PBXGroup section */ 56 | FEF757E21DC82C500070F0C5 = { 57 | isa = PBXGroup; 58 | children = ( 59 | FEEF2C0A1DD44DD80080EFBC /* Conclusion */, 60 | FEF758051DC82CBA0070F0C5 /* Clip */, 61 | FEF757ED1DC82C510070F0C5 /* ClipImage */, 62 | FEF757EC1DC82C500070F0C5 /* Products */, 63 | ); 64 | sourceTree = ""; 65 | }; 66 | FEF757EC1DC82C500070F0C5 /* Products */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | FEF757EB1DC82C500070F0C5 /* ClipImage.app */, 70 | ); 71 | name = Products; 72 | sourceTree = ""; 73 | }; 74 | FEF757ED1DC82C510070F0C5 /* ClipImage */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | FEF757F11DC82C510070F0C5 /* AppDelegate.h */, 78 | FEF757F21DC82C510070F0C5 /* AppDelegate.m */, 79 | FEF757F41DC82C510070F0C5 /* ViewController.h */, 80 | FEF757F51DC82C510070F0C5 /* ViewController.m */, 81 | FEF758091DC834CB0070F0C5 /* ClipViewController.h */, 82 | FEF7580A1DC834CB0070F0C5 /* ClipViewController.m */, 83 | FEF757F71DC82C510070F0C5 /* Main.storyboard */, 84 | FEF757FA1DC82C510070F0C5 /* Assets.xcassets */, 85 | FEF757FC1DC82C510070F0C5 /* LaunchScreen.storyboard */, 86 | FEF757FF1DC82C510070F0C5 /* Info.plist */, 87 | FEF757EE1DC82C510070F0C5 /* Supporting Files */, 88 | ); 89 | path = ClipImage; 90 | sourceTree = ""; 91 | }; 92 | FEF757EE1DC82C510070F0C5 /* Supporting Files */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | FEF757EF1DC82C510070F0C5 /* main.m */, 96 | ); 97 | name = "Supporting Files"; 98 | sourceTree = ""; 99 | }; 100 | FEF758051DC82CBA0070F0C5 /* Clip */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | FEF758061DC82CD90070F0C5 /* ClipImageView.h */, 104 | FEF758071DC82CD90070F0C5 /* ClipImageView.m */, 105 | FEF7580C1DC847500070F0C5 /* ClipAreaView.h */, 106 | FEF7580D1DC847500070F0C5 /* ClipAreaView.m */, 107 | FEF7580F1DCC2CA60070F0C5 /* MidLineView.h */, 108 | FEF758101DCC2CA60070F0C5 /* MidLineView.m */, 109 | ); 110 | path = Clip; 111 | sourceTree = ""; 112 | }; 113 | /* End PBXGroup section */ 114 | 115 | /* Begin PBXNativeTarget section */ 116 | FEF757EA1DC82C500070F0C5 /* ClipImage */ = { 117 | isa = PBXNativeTarget; 118 | buildConfigurationList = FEF758021DC82C510070F0C5 /* Build configuration list for PBXNativeTarget "ClipImage" */; 119 | buildPhases = ( 120 | FEF757E71DC82C500070F0C5 /* Sources */, 121 | FEF757E81DC82C500070F0C5 /* Frameworks */, 122 | FEF757E91DC82C500070F0C5 /* Resources */, 123 | ); 124 | buildRules = ( 125 | ); 126 | dependencies = ( 127 | ); 128 | name = ClipImage; 129 | productName = ClipImage; 130 | productReference = FEF757EB1DC82C500070F0C5 /* ClipImage.app */; 131 | productType = "com.apple.product-type.application"; 132 | }; 133 | /* End PBXNativeTarget section */ 134 | 135 | /* Begin PBXProject section */ 136 | FEF757E31DC82C500070F0C5 /* Project object */ = { 137 | isa = PBXProject; 138 | attributes = { 139 | LastUpgradeCheck = 0730; 140 | ORGANIZATIONNAME = zhaoName; 141 | TargetAttributes = { 142 | FEF757EA1DC82C500070F0C5 = { 143 | CreatedOnToolsVersion = 7.3.1; 144 | DevelopmentTeam = 68JDS85SLB; 145 | }; 146 | }; 147 | }; 148 | buildConfigurationList = FEF757E61DC82C500070F0C5 /* Build configuration list for PBXProject "ClipImage" */; 149 | compatibilityVersion = "Xcode 3.2"; 150 | developmentRegion = English; 151 | hasScannedForEncodings = 0; 152 | knownRegions = ( 153 | en, 154 | Base, 155 | ); 156 | mainGroup = FEF757E21DC82C500070F0C5; 157 | productRefGroup = FEF757EC1DC82C500070F0C5 /* Products */; 158 | projectDirPath = ""; 159 | projectRoot = ""; 160 | targets = ( 161 | FEF757EA1DC82C500070F0C5 /* ClipImage */, 162 | ); 163 | }; 164 | /* End PBXProject section */ 165 | 166 | /* Begin PBXResourcesBuildPhase section */ 167 | FEF757E91DC82C500070F0C5 /* Resources */ = { 168 | isa = PBXResourcesBuildPhase; 169 | buildActionMask = 2147483647; 170 | files = ( 171 | FEF757FE1DC82C510070F0C5 /* LaunchScreen.storyboard in Resources */, 172 | FEF757FB1DC82C510070F0C5 /* Assets.xcassets in Resources */, 173 | FEF757F91DC82C510070F0C5 /* Main.storyboard in Resources */, 174 | FEEF2C0B1DD44DD80080EFBC /* Conclusion in Resources */, 175 | ); 176 | runOnlyForDeploymentPostprocessing = 0; 177 | }; 178 | /* End PBXResourcesBuildPhase section */ 179 | 180 | /* Begin PBXSourcesBuildPhase section */ 181 | FEF757E71DC82C500070F0C5 /* Sources */ = { 182 | isa = PBXSourcesBuildPhase; 183 | buildActionMask = 2147483647; 184 | files = ( 185 | FEF758081DC82CD90070F0C5 /* ClipImageView.m in Sources */, 186 | FEF7580B1DC834CB0070F0C5 /* ClipViewController.m in Sources */, 187 | FEF757F61DC82C510070F0C5 /* ViewController.m in Sources */, 188 | FEF758111DCC2CA60070F0C5 /* MidLineView.m in Sources */, 189 | FEF757F31DC82C510070F0C5 /* AppDelegate.m in Sources */, 190 | FEF757F01DC82C510070F0C5 /* main.m in Sources */, 191 | FEF7580E1DC847500070F0C5 /* ClipAreaView.m in Sources */, 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | /* End PBXSourcesBuildPhase section */ 196 | 197 | /* Begin PBXVariantGroup section */ 198 | FEF757F71DC82C510070F0C5 /* Main.storyboard */ = { 199 | isa = PBXVariantGroup; 200 | children = ( 201 | FEF757F81DC82C510070F0C5 /* Base */, 202 | ); 203 | name = Main.storyboard; 204 | sourceTree = ""; 205 | }; 206 | FEF757FC1DC82C510070F0C5 /* LaunchScreen.storyboard */ = { 207 | isa = PBXVariantGroup; 208 | children = ( 209 | FEF757FD1DC82C510070F0C5 /* Base */, 210 | ); 211 | name = LaunchScreen.storyboard; 212 | sourceTree = ""; 213 | }; 214 | /* End PBXVariantGroup section */ 215 | 216 | /* Begin XCBuildConfiguration section */ 217 | FEF758001DC82C510070F0C5 /* Debug */ = { 218 | isa = XCBuildConfiguration; 219 | buildSettings = { 220 | ALWAYS_SEARCH_USER_PATHS = NO; 221 | CLANG_ANALYZER_NONNULL = YES; 222 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 223 | CLANG_CXX_LIBRARY = "libc++"; 224 | CLANG_ENABLE_MODULES = YES; 225 | CLANG_ENABLE_OBJC_ARC = YES; 226 | CLANG_WARN_BOOL_CONVERSION = YES; 227 | CLANG_WARN_CONSTANT_CONVERSION = YES; 228 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 229 | CLANG_WARN_EMPTY_BODY = YES; 230 | CLANG_WARN_ENUM_CONVERSION = YES; 231 | CLANG_WARN_INT_CONVERSION = YES; 232 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 233 | CLANG_WARN_UNREACHABLE_CODE = YES; 234 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 235 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 236 | COPY_PHASE_STRIP = NO; 237 | DEBUG_INFORMATION_FORMAT = dwarf; 238 | ENABLE_STRICT_OBJC_MSGSEND = YES; 239 | ENABLE_TESTABILITY = YES; 240 | GCC_C_LANGUAGE_STANDARD = gnu99; 241 | GCC_DYNAMIC_NO_PIC = NO; 242 | GCC_NO_COMMON_BLOCKS = YES; 243 | GCC_OPTIMIZATION_LEVEL = 0; 244 | GCC_PREPROCESSOR_DEFINITIONS = ( 245 | "DEBUG=1", 246 | "$(inherited)", 247 | ); 248 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 249 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 250 | GCC_WARN_UNDECLARED_SELECTOR = YES; 251 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 252 | GCC_WARN_UNUSED_FUNCTION = YES; 253 | GCC_WARN_UNUSED_VARIABLE = YES; 254 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 255 | MTL_ENABLE_DEBUG_INFO = YES; 256 | ONLY_ACTIVE_ARCH = YES; 257 | SDKROOT = iphoneos; 258 | }; 259 | name = Debug; 260 | }; 261 | FEF758011DC82C510070F0C5 /* Release */ = { 262 | isa = XCBuildConfiguration; 263 | buildSettings = { 264 | ALWAYS_SEARCH_USER_PATHS = NO; 265 | CLANG_ANALYZER_NONNULL = YES; 266 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 267 | CLANG_CXX_LIBRARY = "libc++"; 268 | CLANG_ENABLE_MODULES = YES; 269 | CLANG_ENABLE_OBJC_ARC = YES; 270 | CLANG_WARN_BOOL_CONVERSION = YES; 271 | CLANG_WARN_CONSTANT_CONVERSION = YES; 272 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 273 | CLANG_WARN_EMPTY_BODY = YES; 274 | CLANG_WARN_ENUM_CONVERSION = YES; 275 | CLANG_WARN_INT_CONVERSION = YES; 276 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 277 | CLANG_WARN_UNREACHABLE_CODE = YES; 278 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 279 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 280 | COPY_PHASE_STRIP = NO; 281 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 282 | ENABLE_NS_ASSERTIONS = NO; 283 | ENABLE_STRICT_OBJC_MSGSEND = YES; 284 | GCC_C_LANGUAGE_STANDARD = gnu99; 285 | GCC_NO_COMMON_BLOCKS = YES; 286 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 287 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 288 | GCC_WARN_UNDECLARED_SELECTOR = YES; 289 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 290 | GCC_WARN_UNUSED_FUNCTION = YES; 291 | GCC_WARN_UNUSED_VARIABLE = YES; 292 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 293 | MTL_ENABLE_DEBUG_INFO = NO; 294 | SDKROOT = iphoneos; 295 | VALIDATE_PRODUCT = YES; 296 | }; 297 | name = Release; 298 | }; 299 | FEF758031DC82C510070F0C5 /* Debug */ = { 300 | isa = XCBuildConfiguration; 301 | buildSettings = { 302 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 303 | CODE_SIGN_IDENTITY = "iPhone Developer"; 304 | INFOPLIST_FILE = ClipImage/Info.plist; 305 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 306 | PRODUCT_BUNDLE_IDENTIFIER = zhaoName.ClipImage; 307 | PRODUCT_NAME = "$(TARGET_NAME)"; 308 | }; 309 | name = Debug; 310 | }; 311 | FEF758041DC82C510070F0C5 /* Release */ = { 312 | isa = XCBuildConfiguration; 313 | buildSettings = { 314 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 315 | CODE_SIGN_IDENTITY = "iPhone Developer"; 316 | INFOPLIST_FILE = ClipImage/Info.plist; 317 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 318 | PRODUCT_BUNDLE_IDENTIFIER = zhaoName.ClipImage; 319 | PRODUCT_NAME = "$(TARGET_NAME)"; 320 | }; 321 | name = Release; 322 | }; 323 | /* End XCBuildConfiguration section */ 324 | 325 | /* Begin XCConfigurationList section */ 326 | FEF757E61DC82C500070F0C5 /* Build configuration list for PBXProject "ClipImage" */ = { 327 | isa = XCConfigurationList; 328 | buildConfigurations = ( 329 | FEF758001DC82C510070F0C5 /* Debug */, 330 | FEF758011DC82C510070F0C5 /* Release */, 331 | ); 332 | defaultConfigurationIsVisible = 0; 333 | defaultConfigurationName = Release; 334 | }; 335 | FEF758021DC82C510070F0C5 /* Build configuration list for PBXNativeTarget "ClipImage" */ = { 336 | isa = XCConfigurationList; 337 | buildConfigurations = ( 338 | FEF758031DC82C510070F0C5 /* Debug */, 339 | FEF758041DC82C510070F0C5 /* Release */, 340 | ); 341 | defaultConfigurationIsVisible = 0; 342 | defaultConfigurationName = Release; 343 | }; 344 | /* End XCConfigurationList section */ 345 | }; 346 | rootObject = FEF757E31DC82C500070F0C5 /* Project object */; 347 | } 348 | -------------------------------------------------------------------------------- /ClipImage.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ClipImage.xcodeproj/xcuserdata/zhao.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ClipImage.xcodeproj/xcuserdata/zhao.xcuserdatad/xcschemes/ClipImage.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ClipImage.xcodeproj/xcuserdata/zhao.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ClipImage.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | FEF757EA1DC82C500070F0C5 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ClipImage.xcodeproj/xcuserdata/zhaosongbo.xcuserdatad/xcschemes/ClipImage.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ClipImage/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /ClipImage/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/QRCodeLine.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "QRCodeLine@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "QRCodeLine@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/QRCodeLine.imageset/QRCodeLine@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/QRCodeLine.imageset/QRCodeLine@2x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/QRCodeLine.imageset/QRCodeLine@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/QRCodeLine.imageset/QRCodeLine@3x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "QRCodeTopLeft@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "QRCodeTopLeft@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow1.imageset/QRCodeTopLeft@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/arrow1.imageset/QRCodeTopLeft@2x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow1.imageset/QRCodeTopLeft@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/arrow1.imageset/QRCodeTopLeft@3x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "QRCodeTopRight@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "QRCodeTopRight@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow2.imageset/QRCodeTopRight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/arrow2.imageset/QRCodeTopRight@2x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow2.imageset/QRCodeTopRight@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/arrow2.imageset/QRCodeTopRight@3x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "QRCodebottomLeft@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "QRCodebottomLeft@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow3.imageset/QRCodebottomLeft@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/arrow3.imageset/QRCodebottomLeft@2x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow3.imageset/QRCodebottomLeft@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/arrow3.imageset/QRCodebottomLeft@3x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "QRCodebottomRight@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "QRCodebottomRight@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow4.imageset/QRCodebottomRight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/arrow4.imageset/QRCodebottomRight@2x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/arrow4.imageset/QRCodebottomRight@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/arrow4.imageset/QRCodebottomRight@3x.png -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/dog.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "dog.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /ClipImage/Assets.xcassets/dog.imageset/dog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipImage/Assets.xcassets/dog.imageset/dog.png -------------------------------------------------------------------------------- /ClipImage/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ClipImage/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /ClipImage/ClipViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClipViewController.h 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol ClipViewControllerDelegate 12 | 13 | - (void)didSuccessClipImage:(UIImage *)clipedImage; 14 | 15 | @end 16 | 17 | @interface ClipViewController : UIViewController 18 | 19 | @property (nonatomic, strong) UIImage *needClipImage; 20 | @property (nonatomic, weak) id delegate; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ClipImage/ClipViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClipViewController.m 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 8 | 9 | #import "ClipViewController.h" 10 | #import "ClipImageView.h" 11 | 12 | #define Screen_Width [UIScreen mainScreen].bounds.size.width 13 | #define Screen_Height [UIScreen mainScreen].bounds.size.height 14 | 15 | @interface ClipViewController () 16 | 17 | @property (nonatomic, strong) ClipImageView *clipImageView; 18 | 19 | @end 20 | 21 | @implementation ClipViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | self.navigationItem.title = @"图片裁剪"; 27 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancelClipImage:)]; 28 | self.navigationItem.rightBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStylePlain target:self action:@selector(successClipImage:)]; 29 | 30 | self.view.backgroundColor = [UIColor whiteColor]; 31 | [self.view addSubview:self.clipImageView]; 32 | self.clipImageView.clipImage = self.needClipImage; 33 | } 34 | 35 | - (void)viewWillAppear:(BOOL)animated 36 | { 37 | [super viewWillAppear:animated]; 38 | // 从相机界面跳转会默认隐藏导航栏 39 | self.navigationController.navigationBarHidden = NO; 40 | } 41 | 42 | // 取消裁剪 43 | - (void)cancelClipImage:(UIBarButtonItem *)sender 44 | { 45 | if([self.delegate respondsToSelector:@selector(didSuccessClipImage:)]) 46 | { 47 | [self.delegate didSuccessClipImage:nil]; 48 | } 49 | } 50 | 51 | // 裁剪成功 52 | - (void)successClipImage:(UIBarButtonItem *)sender 53 | { 54 | UIImage *clipedImage = [self.clipImageView getClipedImage]; 55 | if([self.delegate respondsToSelector:@selector(didSuccessClipImage:)]) 56 | { 57 | [self.delegate didSuccessClipImage:clipedImage]; 58 | } 59 | } 60 | 61 | - (void)didReceiveMemoryWarning 62 | { 63 | NSLog(@"didReceiveMemoryWarning"); 64 | } 65 | 66 | #pragma mark -- getter 67 | 68 | - (ClipImageView *)clipImageView 69 | { 70 | if(!_clipImageView) 71 | { 72 | _clipImageView = [ClipImageView initWithFrame:CGRectMake(0, 100, Screen_Width, 400)]; 73 | //_clipImageView.contentMode = UIViewContentModeScaleAspectFit; 74 | _clipImageView.midLineColor = [UIColor redColor]; 75 | _clipImageView.clipType = ClipAreaViewTypeArc; 76 | } 77 | return _clipImageView; 78 | } 79 | 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /ClipImage/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSCameraUsageDescription 6 | 7 | NSPhotoLibraryUsageDescription 8 | 9 | CFBundleDevelopmentRegion 10 | en 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1 27 | LSRequiresIPhoneOS 28 | 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /ClipImage/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /ClipImage/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "ClipViewController.h" 11 | 12 | @interface ViewController () 13 | 14 | @property (weak, nonatomic) IBOutlet UIImageView *clipedImageView; 15 | - (IBAction)touchClipItem:(UIBarButtonItem *)sender; 16 | 17 | @end 18 | 19 | @implementation ViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | 24 | } 25 | 26 | - (IBAction)touchClipItem:(UIBarButtonItem *)sender 27 | { 28 | [self openCameraOrPhotoLibrary]; 29 | } 30 | 31 | #pragma mark -- 打开相机或相册 32 | 33 | /** 34 | * 打开相机或相册 35 | */ 36 | - (void)openCameraOrPhotoLibrary 37 | { 38 | UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; 39 | [self presentViewController:alertVC animated:YES completion:nil]; 40 | 41 | [alertVC addAction:[UIAlertAction actionWithTitle:@"相机" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 42 | 43 | // 打开相机 比较懒,暂时先这样获取访问权限 44 | if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) 45 | { 46 | [self openWithSourceType:UIImagePickerControllerSourceTypeCamera]; 47 | } 48 | }]]; 49 | 50 | [alertVC addAction:[UIAlertAction actionWithTitle:@"相册" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 51 | 52 | // 打开相册 53 | if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) 54 | { 55 | [self openWithSourceType:UIImagePickerControllerSourceTypePhotoLibrary]; 56 | } 57 | }]]; 58 | 59 | [alertVC addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]]; 60 | } 61 | 62 | // 63 | - (void)openWithSourceType:(UIImagePickerControllerSourceType)sourceType 64 | { 65 | UIImagePickerController *imagePickerVC = [[UIImagePickerController alloc] init]; 66 | imagePickerVC.sourceType = sourceType; 67 | imagePickerVC.delegate = self; 68 | 69 | [self presentViewController:imagePickerVC animated:YES completion:nil]; 70 | } 71 | 72 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 73 | { 74 | ClipViewController *clipVC = [[ClipViewController alloc] init]; 75 | clipVC.delegate = self; 76 | clipVC.needClipImage = [self fixOrientation:info[UIImagePickerControllerOriginalImage]]; 77 | [picker pushViewController:clipVC animated:YES]; 78 | } 79 | 80 | - (UIImage *)fixOrientation:(UIImage *)originalImage 81 | { 82 | if (originalImage.imageOrientation == UIImageOrientationUp) return originalImage; 83 | CGAffineTransform transform = CGAffineTransformIdentity; 84 | 85 | switch (originalImage.imageOrientation) { 86 | case UIImageOrientationDown: 87 | case UIImageOrientationDownMirrored: 88 | transform = CGAffineTransformTranslate(transform, originalImage.size.width, originalImage.size.height); 89 | transform = CGAffineTransformRotate(transform, M_PI); 90 | break; 91 | 92 | case UIImageOrientationLeft: 93 | case UIImageOrientationLeftMirrored: 94 | transform = CGAffineTransformTranslate(transform, originalImage.size.width, 0); 95 | transform = CGAffineTransformRotate(transform, M_PI_2); 96 | break; 97 | 98 | case UIImageOrientationRight: 99 | case UIImageOrientationRightMirrored: 100 | transform = CGAffineTransformTranslate(transform, 0, originalImage.size.height); 101 | transform = CGAffineTransformRotate(transform, -M_PI_2); 102 | break; 103 | case UIImageOrientationUp: 104 | case UIImageOrientationUpMirrored: 105 | break; 106 | } 107 | 108 | switch (originalImage.imageOrientation) { 109 | case UIImageOrientationUpMirrored: 110 | case UIImageOrientationDownMirrored: 111 | transform = CGAffineTransformTranslate(transform, originalImage.size.width, 0); 112 | transform = CGAffineTransformScale(transform, -1, 1); 113 | break; 114 | 115 | case UIImageOrientationLeftMirrored: 116 | case UIImageOrientationRightMirrored: 117 | transform = CGAffineTransformTranslate(transform, originalImage.size.height, 0); 118 | transform = CGAffineTransformScale(transform, -1, 1); 119 | break; 120 | case UIImageOrientationUp: 121 | case UIImageOrientationDown: 122 | case UIImageOrientationLeft: 123 | case UIImageOrientationRight: 124 | break; 125 | } 126 | 127 | CGContextRef ctx = CGBitmapContextCreate(NULL, originalImage.size.width, originalImage.size.height, 128 | CGImageGetBitsPerComponent(originalImage.CGImage), 0, 129 | CGImageGetColorSpace(originalImage.CGImage), 130 | CGImageGetBitmapInfo(originalImage.CGImage)); 131 | CGContextConcatCTM(ctx, transform); 132 | switch (originalImage.imageOrientation) 133 | { 134 | case UIImageOrientationLeft: 135 | case UIImageOrientationLeftMirrored: 136 | case UIImageOrientationRight: 137 | case UIImageOrientationRightMirrored: 138 | CGContextDrawImage(ctx, CGRectMake(0,0,originalImage.size.height,originalImage.size.width), originalImage.CGImage); 139 | break; 140 | 141 | default: 142 | CGContextDrawImage(ctx, CGRectMake(0,0,originalImage.size.width,originalImage.size.height), originalImage.CGImage); 143 | break; 144 | } 145 | 146 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 147 | UIImage *img = [UIImage imageWithCGImage:cgimg]; 148 | CGContextRelease(ctx); 149 | CGImageRelease(cgimg); 150 | return img; 151 | } 152 | 153 | #pragma mark -- ClipViewControllerDelegate 154 | 155 | - (void)didSuccessClipImage:(UIImage *)clipedImage 156 | { 157 | self.clipedImageView.backgroundColor = [UIColor redColor]; 158 | self.clipedImageView.contentMode = UIViewContentModeScaleAspectFit; 159 | self.clipedImageView.image = clipedImage; 160 | 161 | [self dismissViewControllerAnimated:YES completion:nil]; 162 | } 163 | 164 | @end 165 | -------------------------------------------------------------------------------- /ClipImage/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ClipImage 4 | // 5 | // Created by zhao on 16/11/1. 6 | // Copyright © 2016年 zhaoName. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ClipRectImage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoName/ClipImage/86ee9b569ac294c97e9ed547b91deee935619de4/ClipRectImage.gif -------------------------------------------------------------------------------- /Conclusion: -------------------------------------------------------------------------------- 1 | 2 | 图片裁剪包括矩形和圆形两种(ClipAreaViewType)。 3 | 4 | 矩形:图片不可移动,裁剪框支持缩放、四个拐角点击控制裁剪框大小、四个中间线点击控制裁剪框大小。 5 | 6 | 1、由于四个拐角和中间线相对于裁剪区域来说,位置都是固定的,所以无论是点击点击四个拐角还是点击四条中间线都可以直接裁剪区域frame的变化(注意能变化的范围),然后用KVO监测frame或center,重新计算四个拐角和中间线就可以。 7 | 8 | 2、中间线的实际高度(MID_LINE_INVISIBLE)比看到的(MID_LINE_HEIGHT)大,而且没有留外部接口,可以自定义颜色 9 | 10 | 3、矩形框裁剪要注意CGImageCreateWithImageInRect这个方法的第二个参数,是按实际图片的size算的,要注意换算 11 | 12 | 13 | 圆形:裁剪区域不可移动,图片支持单个手指移动,两个手指缩放。 14 | 15 | 1、除了要注意CGImageCreateWithImageInRect,*****还要注意缩放图片后,裁剪区域相对于图片的坐标也要变化***** 16 | 17 | 18 | 19 | 参考: 20 | 图片方向:http://www.cocoachina.com/ios/20150605/12021.html 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ClipImage 2 | 图片裁剪 3 | 4 | 支持矩形和圆形两种方式:ClipAreaViewType 5 | 6 | 已知bug:在iOS8.1模拟器下,由于-(void)layoutSubviews被调用两次导致KVO监测加载两次,而KVO只remove一次,从而导致crash。 7 | 暂时解决方案:判断版本,iOS9之前的版本KVO释放两次。 或者有那啥大的 给我提点提点。。。。 8 | 9 | ![image](https://github.com/zhaoName/ClipImage/blob/master/ClipRectImage.gif) 10 | 11 | 12 | 但是在加载相册中的图片内存会增加很多,有知道的可以给我说一下。。。 13 | --------------------------------------------------------------------------------