一个图片裁剪控件

这篇文章就是介绍开篇说的图片裁剪视图的构建。

 

      

  效果图如上图所示. 要求:

  1. 裁剪框是正方形, 要求保持位置, 大小不变.
  2. 底图可以放大, 缩小,旋转.
  3. 底图在缩小时, 无论怎么缩小. 都要保持最小边不能超过正方形的边长. 即不能出现黑边. 要保持图片始终能够填充正方形.
  4. 当图片大于正方形时, 底图能随意左右上下滑动. 使边缘能够与正方形对齐.

   首先, 初步分析需求. 缩放操作可以利用ScollView的Zoom属性来实现. 旋转可以利用UIView的TransForm来实现. 感觉很简单. 确实. 

  但是, 怎么拼合这3个视图的关系, 才能在进行缩放, 拖动的时候知道选择区与ImageView的相对坐标呢? 以此我们通过DrawInRect函数正确输出选择的图片?

 

  View Hierarchy:

  

  

  经过一番分析和实验, (这里忽略了如何解决这个问题的过程, 因为写起来很复杂.)最终可以实现的方法如下:

  • UIScrollView:
    • 大小与选择区保持一致  (这样我们不需要设置ContentInset属性来满足需求4, 因为在缩放的过程中ContentInset会影响最终位置的计算)
    • clipsToBounds属性改为NO (UIScrollView默认为YES, 这个是关键)
    • 设置ContentSize大小为UIImageView的宽和高. (这样可以满足需求4)
    • 设置ContentOffset, 使UIImageView初始在居中位置
    • 设置最小缩放比例为1, 最大缩放比例为3(可以随意设置).
  • UIImageView:
    • 长宽比与图片保持一致, 且最小边与选择区的边长保持一致. 

  以上这样做的好处就是, 直接利用ScrollView的ContentOffset属性就可以轻易的知道选择区在图片上的相对位置. 如下.

CGRectMake(-_scrollView.contentOffset.x, -_scrollView.contentOffset.y, _scrollView.contentSize.width, _scrollView.contentSize.height);

  整个裁剪的代码:

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(320, 320), 1, 1);
    CGRect drawRect = CGRectMake(-_scrollView.contentOffset.x, -_scrollView.contentOffset.y, _scrollView.contentSize.width, _scrollView.contentSize.height);
    [origionImage drawInRect:drawRect];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

 

  一目了然, 相当简便, 省去了诸多宽高的反复计算. 也不用来回倒腾UIImageView和ScrollView的几何属性.

 

  对于需求2的旋转操作. 每当进行一次旋转的时候, 我们只是让ScrollView(而不是ImageView)进行旋转, 如下:

- (void)rotateClockWise90Degree
{
    _rotateCounter++;
    [_scrollView setZoomScale:1.f];
    
    CGAffineTransform rotateTranform = CGAffineTransformRotate(_scrollView.transform, M_PI_2);
    [UIView animateWithDuration:.25f animations:^{
        _scrollView.transform = rotateTranform;
    }];
}

 

  旋转后的裁剪, 我们依然使用前面的裁剪代码. 这样裁剪的坐标系始终是ScrollView的坐标系. 然后我们图像做一次旋转, 这里有个技巧, 我们不需设置绘制Context的Transfrom, 并对Image进行重新DrawRect. 我们可以调用系统的一个函数, 一段语句完成这个操作, 如下.

image = [UIImage imageWithCGImage:image.CGImage scale:image.scale orientation:orientation];

  非常简单. 当然orientation参数是通过旋转次数计算出来的.

  这样所有的操作最终简练成2段语句

CGRect drawRect = CGRectMake(-_scrollView.contentOffset.x, -_scrollView.contentOffset.y, _scrollView.contentSize.width, _scrollView.contentSize.height);

与

image = [UIImage imageWithCGImage:image.CGImage scale:image.scale orientation:orientation];

 

  

  所以, 只要提前设计好了需求的实现, 代码写起来也是想当的方便易懂.

  代码下载地址: DownLoad

 

 

 

posted @ 2014-02-13 16:53  John的Blog  阅读(287)  评论(2编辑  收藏  举报