嘗試用STAR法則寫一篇小白Demo园蝠,關(guān)于自定義圖片切割功能
固定裁切框大小歼疮,圖片可拖動縮放跃捣,精準(zhǔn)裁切.
源碼在最后
STAR法則是情境(situation)枷颊、任務(wù)(task)、行動(action)徽职、結(jié)果(result)
情境(situation)
需要一個裁切固定尺寸圖片的功能象颖,類似這樣
任務(wù)(task)
封裝一個View,需要以下功能
可以接受選擇的圖片顯示
圖片編輯完成后給出圖片的裁切范圍
圖片可以放大姆钉,縮小说订,拖動,且活動范圍在給定的裁切框范圍內(nèi)
行動(action)
從任務(wù)預(yù)期來看
首先需要給出一個參數(shù) image 用來接收外界傳過來的參數(shù)
在image做完交互后傳出對應(yīng)到原始image 的Frame潮瓶,切割用
因為圖片需要有放大縮小拖動的交互陶冷,所以自然想到可以把圖片放到 UIScrollView 容器內(nèi),為了方便說明,整個裁切的結(jié)構(gòu)層級如下
- 1 是用UIScrollView做容器
- 2 是添加一個UIImageView用來展示圖片
- 3 是一個UIView毯辅,作為一個遮罩
- 4 是一個自定義的UIView埂伦,裁切框,這個Frame很關(guān)鍵
- 比較關(guān)鍵的一些點
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.backgroundContainerView;
//這里 backgroundContainerView 是imageView的容器思恐,實現(xiàn)這個代理保證圖片的放大拖動交互
}
self.scrollView.contentInset = (UIEdgeInsets){CGRectGetMinY(contentRect),
CGRectGetMinX(contentRect),
CGRectGetMaxY(self.bounds) - CGRectGetMaxY(contentRect),
CGRectGetMaxX(self.bounds) - CGRectGetMaxX(contentRect)};
contentRect 是裁切框Frame
這里的偏移量 scrollView.contentInset 用來保證圖片不滑出 裁切框外
self.scrollView.minimumZoomScale = scale;
self.scrollView.maximumZoomScale = 15.0f;
self.scrollView.zoomScale = self.scrollView.minimumZoomScale;
這里設(shè)置 scrollView 最大和最小縮放范圍沾谜,這里的scale獲取以屏幕寬為主
比如. 一個原始大小為 750*1330 的圖片,scale 為 375/750
-(CAShapeLayer *)shaperLayer
{
if (!_shaperLayer) {
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[path appendPath:[[UIBezierPath bezierPathWithRoundedRect:self.cropBoxFrame cornerRadius:1] bezierPathByReversingPath]];
_shaperLayer = [CAShapeLayer layer];
_shaperLayer.path = path.CGPath;
}
return _shaperLayer;
}
cropBoxFrame 是裁切框的Frame胀莹,這里返回的是遮罩的鏤空層,添加到遮罩層上
- 獲取到交互后的圖片 對應(yīng)到 原始圖片坐標(biāo)點和大小
- (CGRect)croppedImageFrame
{
CGSize imageSize = self.imageSize;
CGSize contentSize = self.scrollView.contentSize;
CGRect cropBoxFrame = self.cropBoxFrame;
CGPoint contentOffset = self.scrollView.contentOffset;
UIEdgeInsets edgeInsets = self.scrollView.contentInset;
CGRect frame = CGRectZero;
frame.origin.x = floorf((contentOffset.x + edgeInsets.left) * (imageSize.width / contentSize.width));
frame.origin.x = MAX(0, frame.origin.x);
frame.origin.y = floorf((contentOffset.y + edgeInsets.top) * (imageSize.height / contentSize.height));
frame.origin.y = MAX(0, frame.origin.y);
frame.size.width = ceilf(cropBoxFrame.size.width * (imageSize.width / contentSize.width));
frame.size.width = MIN(imageSize.width, frame.size.width);
frame.size.height = ceilf(cropBoxFrame.size.height * (imageSize.height / contentSize.height));
frame.size.height = MIN(imageSize.height, frame.size.height);
return frame;
}
要知道圖片的原始尺寸 與 scrollView.contentSize 的比例基跑,
然后通過 contentOffset 算出 在對應(yīng)比例下圖片的移動位置,得到要切割的起始坐標(biāo)
結(jié)果(result)
- 使用
PPMainCropVC *vc = [[PPMainCropVC alloc]initWithImage:[UIImage imageNamed:@"1.png"]];
vc.cropBlock = ^(UIImage *image) {
[self.mainImageView setImage:image];
};
[self.navigationController pushViewController:vc animated:YES];
在裁切頁面隱藏了導(dǎo)航欄和狀態(tài)欄描焰,如果圖片拖動與裁切框有偏移媳否,看看Info.plist 中 , 設(shè)置 View controller-based status bar appearance 為NO,該參數(shù)決定我們項目狀態(tài)欄的顯隱藏是否以各控制器的設(shè)置為準(zhǔn)篱竭。