这篇文章就是介绍开篇说的图片裁剪视图的构建。
效果图如上图所示. 要求:
- 裁剪框是正方形, 要求保持位置, 大小不变.
- 底图可以放大, 缩小,旋转.
- 底图在缩小时, 无论怎么缩小. 都要保持最小边不能超过正方形的边长. 即不能出现黑边. 要保持图片始终能够填充正方形.
- 当图片大于正方形时, 底图能随意左右上下滑动. 使边缘能够与正方形对齐.
首先, 初步分析需求. 缩放操作可以利用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];
所以, 只要提前设计好了需求的实现, 代码写起来也是想当的方便易懂.
代码下载地址: