項目中要用到,選取圖庫或者拍照的圖片,而後截取固定的尺寸做爲頭像,當時是使用第三方庫GKImagePicker,可是其中的bug,弄了半天也修不了,而且感受它的這個功能的代碼作的太複雜了,全部本身寫了一個相似功能的。ios
這裏主要記錄過程當中發現的一些東西:app
scrollview縮放後,其frame不變,sourceImage的frame會被縮放到須要的大小,scrollview的contentsize不論以前是多少,在縮放後,會和sourceImage的frame同樣大小。atom
截取內容尺寸大小,須要乘以一個比例,這個比例是image的frame大小和image實際圖像大小的比例。spa
scrollview若是contentoffset是處於邊界了,就沒法移動,不論加在上面的sourceImage有多大,都會被彈回,而contentsize的默認座標也只能是(0,0)。code
@interface CropImageView : UIView<UIScrollViewDelegate> { UIImageView* _sourceImage; UIScrollView* _scrollView; UIView* _maskView; CGFloat _addWidth; CGFloat _addHeight; } @property(nonatomic, strong) UIImage* inputImage; @property(nonatomic, strong) UIImage* outputImage; // 裁剪須要的尺寸,會居中顯示 @property(nonatomic, assign) CGSize cropSize;
#define SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width #define SCREEN_HEIGHT [[UIScreen mainScreen] bounds].size.height #import "CropImageView.h" @implementation CropImageView - (UIImage *)outputImage { CGFloat w_faktor = _sourceImage.image.size.width / _sourceImage.frame.size.width; CGFloat h_faktor = _sourceImage.image.size.height / _sourceImage.frame.size.height; CGFloat x = _scrollView.contentOffset.x * w_faktor; CGFloat y = _scrollView.contentOffset.y * h_faktor; CGRect myImageRect = CGRectMake(x, y, _cropSize.width * w_faktor, _cropSize.height * h_faktor); CGImageRef sourceImageRef = [_sourceImage.image CGImage]; CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, myImageRect); UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; CGImageRelease(newImageRef); return newImage; } - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return _scrollView; } - (void)layoutSubviews { [super layoutSubviews]; _scrollView = [[UIScrollView alloc] init]; _scrollView.backgroundColor = [UIColor greenColor]; // scrollview的frame這裏只是暫時設置 _scrollView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); _scrollView.clipsToBounds = NO; _scrollView.delegate = self; _scrollView.minimumZoomScale = 1.0f; _scrollView.maximumZoomScale = 20.0f; [_scrollView setZoomScale:1.0f]; [self addSubview:_scrollView]; CGFloat resultHeight, resultWidth; // 把圖片進行壓縮,但要比例不變 if (_inputImage.size.width > SCREEN_WIDTH) { if (_inputImage.size.width > _inputImage.size.height) { CGFloat faktor = _inputImage.size.width / SCREEN_WIDTH; resultWidth = SCREEN_WIDTH; resultHeight = _inputImage.size.height / faktor; } } else if (_inputImage.size.height > SCREEN_HEIGHT) { if (_inputImage.size.height > _inputImage.size.width) { CGFloat faktor = _inputImage.size.height / SCREEN_HEIGHT; resultHeight = SCREEN_HEIGHT; resultWidth = _inputImage.size.width / faktor; } } else { resultWidth = _inputImage.size.width; resultHeight = _inputImage.size.height; } // 計算位置,也要居中 CGFloat x = (_scrollView.frame.size.width - resultWidth) / 2; CGFloat y = (_scrollView.frame.size.height - resultHeight) / 2; // 補差,由於裁剪的顯示位置也會居中,那如何讓image的各個部分均可以滾動到裁剪位置內呢,這就須要補差 CGFloat addWidth = 0, addHeight = 0; if (resultWidth > _cropSize.width) { addWidth = (resultWidth - _cropSize.width) / 2; } if (resultHeight > _cropSize.height) { addHeight = (resultHeight - _cropSize.height) / 2; } _addWidth = addWidth; _addHeight = addHeight; _scrollView.frame = CGRectMake(x, y, resultWidth, resultHeight); _scrollView.contentSize = CGSizeMake(resultWidth + 2 * addWidth, resultHeight + 2 * addHeight); _sourceImage = [[UIImageView alloc] initWithImage:_inputImage]; _sourceImage.backgroundColor = [UIColor brownColor]; _sourceImage.frame = CGRectMake(addWidth, addHeight, resultWidth, resultHeight); [_scrollView addSubview:_sourceImage]; _scrollView.contentOffset = CGPointMake(addWidth, addHeight); // 最上層的view,用來做爲遮罩 _maskView = [[UIView alloc] initWithFrame:self.bounds]; _maskView.backgroundColor = [UIColor blackColor]; _maskView.alpha = 0.6; _maskView.userInteractionEnabled = NO; [self addSubview:_maskView]; x = (SCREEN_WIDTH - _cropSize.width) / 2; y = (SCREEN_HEIGHT - _cropSize.height) / 2; // 顯示出裁剪位置尺寸 UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)]; // 這個方法在ios7下有問題,會變成三角形,具體緣由不知,替代方法是換成圓角矩形,把圓角角度設爲0 // [path appendPath:[[UIBezierPath bezierPathWithRoundedRect:CGRectMake(x, y, _cropSize.width, _cropSize.height) byRoundingCorners:0 cornerRadii:CGSizeZero] bezierPathByReversingPath]]; [path appendPath:[[UIBezierPath bezierPathWithRect:CGRectMake(x, y, _cropSize.width, _cropSize.height)] bezierPathByReversingPath]]; CAShapeLayer *shapeLayer = [CAShapeLayer layer]; shapeLayer.path = path.CGPath; _maskView.layer.mask = shapeLayer; } - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return _sourceImage; } - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { CGSize recontentSize = CGSizeMake(_scrollView.contentSize.width + _addWidth * 2, _scrollView.contentSize.height + _addHeight * 2); _scrollView.contentSize = recontentSize; }