[STAR]简洁的图片裁切


尝试用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很关键
[STAR]简洁的图片裁切_第1张图片

  • 比较关键的一些点
-(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];

  • 源码在这,具体效果请运行Demo

  • 在裁切页面隐藏了导航栏和状态栏,如果图片拖动与裁切框有偏移,看看Info.plist 中 , 设置 View controller-based status bar appearance 为NO,该参数决定我们项目状态栏的显隐藏是否以各控制器的设置为准。

你可能感兴趣的:([STAR]简洁的图片裁切)