尝试用STAR法则写一篇小白Demo,关于自定义图片切割功能
固定裁切框大小,图片可拖动缩放,精准裁切.
源码在最后
STAR法则是情境(situation)、任务(task)、行动(action)、结果(result)
情境(situation)
需要一个裁切固定尺寸图片的功能,类似这样
任务(task)
封装一个View,需要以下功能
-
可以接受选择的图片显示
-
图片编辑完成后给出图片的裁切范围
-
图片可以放大,缩小,拖动,且活动范围在给定的裁切框范围内
行动(action)
从任务预期来看
首先需要给出一个参数 image 用来接收外界传过来的参数
在image做完交互后传出对应到原始image 的Frame,切割用
因为图片需要有放大缩小拖动的交互,所以自然想到可以把图片放到 UIScrollView 容器内,为了方便说明,整个裁切的结构层级如下
- 1 是用UIScrollView做容器
- 2 是添加一个UIImageView用来展示图片
- 3 是一个UIView,作为一个遮罩
- 4 是一个自定义的UIView,裁切框,这个Frame很关键
- 比较关键的一些点
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.backgroundContainerView;
//这里 backgroundContainerView 是imageView的容器,实现这个代理保证图片的放大拖动交互
}
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;
这里设置 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,这里返回的是遮罩的镂空层,添加到遮罩层上
- 获取到交互后的图片 对应到 原始图片坐标点和大小
- (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 算出 在对应比例下图片的移动位置,得到要切割的起始坐标
结果(result)
- 使用
PPMainCropVC *vc = [[PPMainCropVC alloc]initWithImage:[UIImage imageNamed:@"1.png"]];
vc.cropBlock = ^(UIImage *image) {
[self.mainImageView setImage:image];
};
[self.navigationController pushViewController:vc animated:YES];
-
在裁切页面隐藏了导航栏和状态栏,如果图片拖动与裁切框有偏移,看看Info.plist 中 , 设置 View controller-based status bar appearance 为NO,该参数决定我们项目状态栏的显隐藏是否以各控制器的设置为准。
网友评论