IOS的UIImagePickerController可以让用户通过相机或者相册获取想要的图片,并且通过设置allowsEditing属性允许用户在选择了图片以后对图片进行裁剪。不过在某些时候会出现正方形的裁剪框没有适配图片的情况,如下图:

这时候裁剪得到的是一张长方形图片,并且图片尺寸与UIImagePickerController设置的maxWidth和maxHeight尺寸并不符合。例如一个高和宽比例为1:2的图片,设置裁剪的maxWidth和maxHeight均为100,裁剪框的范围类似于上面右边的图片,上下留空左右框住图片的边界。最终获取到的裁剪结果为一张宽为100高为200的长方形图片。

现在需要一个图片裁剪器,能够自适应图片最窄边的裁剪,保证最终得到的图片为正方形。综合网上查询结果,决定做一个类似WP7系统自带的裁剪方案:一个固定的透明框在屏幕中央,周围留黑色遮罩,允许用户随意缩放和移动图片,不过图片的边界不会超出屏幕中的透明框。

首先考虑裁剪框,需要固定在屏幕中间不动,并且周围是透明的遮罩,决定采用UIImageView显示一张图片在屏幕的最顶层。裁剪器在我这里实际的用途为裁剪头像,定义的标准为两种,720X720的高清头像和300X300的普通头像。因此透明框的大小我选择了300X300,在屏幕中居中。

为了实现图片的滑动和缩放,选择UIScrollView作为容器来装显示用户图片的ImageView。为了保证图片边界不超出裁剪框范围,需要根据图片的长宽来定义ScrollView的ContentSize,并适应缩放。代码中我重写了SourceImage的Set方法,在Set方法中适配好图片显示和ContentSize的大小。并且在缩放倍数上作限制,如果图片本身的最短边就不足720则禁止缩放,如果超过720则最大允许缩放到裁剪框内画面的实际大小为720大小。

ContentView要根据image的大小调整,保证图片不会超出裁剪框。ContentView过大和过小都会影响裁剪。

View Code

1 - (void)setSourceImage:(UIImage *)image{2 if(sourceImage) {3 [sourceImage release];4 sourceImage =nil;5 }6 sourceImage =[image retain];7 [_imageview setImage:self.sourceImage];8 CGFloat wh = sourceImage.size.width/sourceImage.size.height;9 CGSize displaySize;10 if (wh > 1) {//宽图

11 _imageContainer.maximumZoomScale = ((sourceImage.size.height / DEF_CUTSIZE > 1)&&(sourceImage.size.height / DEF_CUTSIZE)*(DEF_CUTSIZE/DEF_HDSIZE) > 1) ? (sourceImage.size.height / DEF_CUTSIZE)*(DEF_CUTSIZE/720) : 1;//设置放大倍数

12 isImgAvailable = (sourceImage.size.height*2 < DEF_CUTSIZE) ? NO : YES;//检查图片是否可用

13 displaySize = CGSizeMake(sourceImage.size.width*(DEF_CUTSIZE/sourceImage.size.height), DEF_CUTSIZE);14 }else{//高图

15 _imageContainer.maximumZoomScale = ((sourceImage.size.width / DEF_CUTSIZE > 1)&&(sourceImage.size.width / DEF_CUTSIZE)*(DEF_CUTSIZE/DEF_HDSIZE) > 1) ? (sourceImage.size.width / DEF_CUTSIZE)*(DEF_CUTSIZE/720) : 1;//设置放大倍数

16 isImgAvailable = (sourceImage.size.width*2 < DEF_CUTSIZE) ? NO : YES;//检查图片是否可用

17 displaySize = CGSizeMake(DEF_CUTSIZE, sourceImage.size.height*(DEF_CUTSIZE/sourceImage.size.width));18 }19 _imageview.frame = CGRectMake(0, 0, displaySize.width, displaySize.height);20 _imageContainer.contentSize =_imageview.frame.size;21 _imageContainer.contentInset = UIEdgeInsetsMake((SCREEN_HEIGHT - DEF_CUTSIZE)/2, (SCREEN_WIDTH - DEF_CUTSIZE)/2, (SCREEN_HEIGHT - DEF_CUTSIZE)/2, (SCREEN_WIDTH - DEF_CUTSIZE)/2);22

23 //让图片居中显示

24 _imageContainer.contentOffset = (wh>1) ? CGPointMake((displaySize.width - SCREEN_WIDTH)/2, _imageContainer.contentOffset.y) : CGPointMake(_imageContainer.contentOffset.x, (displaySize.height - SCREEN_HEIGHT)/2);25 }

图片的拖动和缩放做好以后,剩下的就是裁剪了。裁剪方法是从网上抄来的代码,全网都在转载不知具体出处了。定义好裁剪区域的大小和起始坐标就可以得到裁剪完成的图片了。

View Code

1 CGPoint point = CGPointMake(_imageContainer.contentOffset.x + (SCREEN_WIDTH - DEF_CUTSIZE)/2, _imageContainer.contentOffset.y + (SCREEN_HEIGHT - DEF_CUTSIZE)/2);2 CGRect imageRect = CGRectMake(point.x * (self.sourceImage.size.width / _imageview.frame.size.width), point.y * (self.sourceImage.size.height / _imageview.frame.size.height), DEF_CUTSIZE * (self.sourceImage.size.width / _imageview.frame.size.width), DEF_CUTSIZE * (self.sourceImage.size.height /_imageview.frame.size.height));3 subImage =[self getImageFromImage:self.sourceImage subImageSize:imageRect.size subImageRect:imageRect];4

5

6 //图片裁剪

7 -(UIImage *)getImageFromImage:(UIImage*) superImage subImageSize:(CGSize)subImageSize subImageRect:(CGRect)subImageRect {8 //CGSize subImageSize = CGSizeMake(WIDTH, HEIGHT);//定义裁剪的区域相对于原图片的位置9 //CGRect subImageRect = CGRectMake(START_X, START_Y, WIDTH, HEIGHT);

10 CGImageRef imageRef =superImage.CGImage;11 CGImageRef subImageRef =CGImageCreateWithImageInRect(imageRef, subImageRect);12 UIGraphicsBeginImageContext(subImageSize);13 CGContextRef context =UIGraphicsGetCurrentContext();14 CGContextDrawImage(context, subImageRect, subImageRef);15 UIImage* returnImage =[UIImage imageWithCGImage:subImageRef];16 UIGraphicsEndImageContext(); //返回裁剪的部分图像

17 returnreturnImage;18 }

最后添加一个动画效果,模仿Path软件中看图片的动画,将裁剪框周围的遮罩渐变为全黑,只保留裁剪好的图片,最后裁剪好的图片逐渐缩小到显示头像的地方。为了实现这个效果,在裁剪器中添加一个CGRect属性,生成裁剪器时设置好返回头像位置的坐标和大小,采用UIView的animateWithDuration方法实现动画效果即可。

在裁剪好了以后,头像位置显示的为300X300的小头像,因此增加一个查看720X720高清头像的方法。模仿Path查看图片的渐变动画效果,页面中头像以外的其他元素渐变至全黑,同时将头像放大到屏幕大小。实现方法为用一个新的Controller来显示头像变大变小的动画和展示大图,原页面的小头像仅响应点击。在presentViewController到新的Controller时会挡住原页面,为了实现半透明的渐变效果,需要设置原页面Controler的modalPresentionStyle属性为UIModalPresentationCurrentContext。新的Controller将实现进入和退出动画,在大图显示的时候点击屏幕执行退出动画。

View Code

1 //

2 //AvatarHDViewController.h3 //CutPicTest4 //

5 //Created by liulu on 12-12-21.6 //Copyright (c) 2012年 liulu. All rights reserved.7 //8

9 #import "AvatarHDViewController.h"

10 #import "AppDelegate.h"

11 #import

12

13 #define SCREEN_WIDTH 320

14 #define SCREEN_HEIGHT 480

15

16 @interfaceAvatarHDViewController ()17

18 @end

19

20 @implementationAvatarHDViewController21 @synthesizeavatarImg;22 @synthesizebeginRect;23 @synthesize delegate;24

25 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil26 {27 self =[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];28 if(self) {29 //Custom initialization

30 isShowHDImg =NO;31 self.view.backgroundColor =[UIColor clearColor];32

33 _viewBg = [[UIView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];34 [self.view addSubview:_viewBg];35 [self.view sendSubviewToBack:_viewBg];36 _viewBg.backgroundColor =[UIColor blackColor];37 _viewBg.alpha = 0;38 }39 returnself;40 }41

42 - (void)viewDidLoad43 {44 [super viewDidLoad];45 //Do any additional setup after loading the view.

46 _avatarImgV =[[UIImageView alloc]init];47 [self.view addSubview:_avatarImgV];48 [_avatarImgV.layer setMasksToBounds:YES];49 //[_avatarImgV.layer setCornerRadius:6.0];

50

51 _avatarImgV.contentMode =UIViewContentModeScaleAspectFill;52

53 }54

55 -(void)viewDidAppear:(BOOL)animated{56 [super viewDidAppear:animated];57 [self enterAnimation];58 }59

60 - (void)dealloc{61 [_avatarImgV release];62 [super dealloc];63 }64

65 #pragma mark -

66 #pragma mark set

67 - (void)setAvatarImg:(UIImage *)img{68 avatarImg =img;69 [_avatarImgV setImage:self.avatarImg];70 }71

72 - (void)setBeginRect:(CGRect)rect{73 beginRect =rect;74 _avatarImgV.frame =self.beginRect;75 }76

77 #pragma mark -

78 #pragma mark Animation

79 - (void)enterAnimation{80 //[UIView animateWithDuration:0.2 animations:^{81 //_viewBg.alpha = 1;82 //}completion:^(BOOL finished){83 //if (finished) {

84 [UIView animateWithDuration:0.5 animations:^{85 _avatarImgV.frame = CGRectMake(0, (SCREEN_HEIGHT - SCREEN_WIDTH)/2, SCREEN_WIDTH, SCREEN_WIDTH);86 _viewBg.alpha = 1;87 }completion:^(BOOL finished){88 if(finished) {89 //添加手势

90 if (!_recognizer) {91 _recognizer =[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeFromDownToUp)];92 }93 [_recognizer setNumberOfTapsRequired:1];94 [_recognizer setNumberOfTouchesRequired:1];95 [self.view addGestureRecognizer:_recognizer];96 }97 }];98 //}99 //}];

100 }101

102 - (void)exitAnimation{103 //[UIView animateWithDuration:0.4 animations:^{104 //_avatarImgV.frame = self.beginRect;105 //}completion:^(BOOL finished){106 //if (finished) {

107 [UIView animateWithDuration:0.5 animations:^{108 _viewBg.alpha = 0;109 _avatarImgV.frame =self.beginRect;110 }completion:^(BOOL finished){111 if (self.delegate&&[self.delegaterespondsToSelector:@selector(hiddenHDUserImg)]) {112 [self.delegatehiddenHDUserImg];113 }114 }];115 //}116 //}];

117 }118

119 - (void)handleSwipeFromDownToUp{120 //移除手势

121 for (UITapGestureRecognizer* recognizer inself.view.gestureRecognizers) {122 if (recognizer==_recognizer) {123 [self.view removeGestureRecognizer:recognizer];124 }125 }126 [self exitAnimation];127 }128

129 - (void)didReceiveMemoryWarning130 {131 [super didReceiveMemoryWarning];132 //Dispose of any resources that can be recreated.

133 }134

135 @end

最终效果:

因为设计的时候考虑不足,在真机上拍照以后可能出现裁剪得到的图片与裁剪框中不同的问题,这是因为ios的相机并没有根据拍照时的重力方向来将图片实际旋转,而是采用了写入图片EXIF信息的方式确保图片显示方向正确。因此在裁剪图片时还需要根据从相册获取到的UIImage对象的imageOrientation来重新计算正确的裁剪坐标和区域才能得到正确的图像。

最终我的这个裁剪器还是没有在实际当中使用,原因是为了适配高清图片,在图片最小边不足720时我直接禁止用户放大了,导致用户体验非常不好。而应用在设置头像的场景中时很多时候对于一张照片用户确实就只想截取其中的某个区域作为头像,而用户很少会在意头像是否是绝对的高清。并且300的尺寸和720的尺寸在大部分手机屏幕上实际上看起来差别并不大。设计时更应该全面考虑实际应用情况,720的分辨率只应该作为高清头像的一个上限标准,而不该强制用户使用720分辨率头像。

ios 图片居中裁剪_IOS图片裁剪和小图看大图动画相关推荐

  1. 前端开发css中怎么让图片居中?css图片居中的方法总结

    在进行网页布局的时候,有时候图片的位置可能会影响整个页面的美观程度,所以对于图片的放置位置就得变化,那么,接下来的这篇文章将给大家来介绍关于图片在网页中如何使用css实现居中的方法,对于有需要的朋友来 ...

  2. css中怎么让图片居中?css图片居中的方法总结

    在进行网页布局的时候,有时候图片的位置可能会影响整个页面的美观程度,所以对于图片的放置位置就得变化,那么,接下来的这篇文章将给大家来介绍关于图片在网页中如何使用css实现居中的方法,对于有需要的朋友来 ...

  3. php图片点击查看大图,jQuery点击小图看大图,大图查看内容详情所有图片

    jQuery点击小图看大图,大图查看内容详情所有图片: html代码如下: × < > CSS代码如下: * { margin:0; padding:0; } body { overflo ...

  4. ios xib 初始化高度_iOS图片伸缩技巧

    纵观移动市场,一款移动app,要想长期在移动市场立足,最起码要包含以下几个要素:实用的功能.极强的用户体验.华丽简洁的外观.华丽外观的背后,少不了美工的辛苦设计,但如果开发人员不懂得怎么合理展示这些设 ...

  5. CSDN写博客修改图片大小、图片居中、去掉图片水印等方法

    CSDN写文章技巧 修改为指定尺寸 图片居中显示 图片底部插入题注 段落前面空格 图片居中自定义大小 两张或者多张图片并排在一起 不同颜色字体 一.修改图片为指定大小 计划将该图片缩放为指定尺寸,需要 ...

  6. 手机端扣扣浏览器图片居中_实现图片始终居中显示于浏览器窗口中心位置

    盒模型 在敲代码之前,首先建立一个盒模型,这让写代码的时候变得思路清晰. 本案例中,所要实现的是图片居中显示,超出浏览器窗口部分的图片隐藏.因此,盒模型如图: 图片以浏览器窗口作为定位元素,居中显示. ...

  7. androidstudio图片居中_Android imageView图片按比例缩放-Fun言

    android:scaleType可控制图片的缩放方式,示例代码如下:说明:centerInside表示按比例缩放图片,使得图片长 (宽)的小于等于视图的相应维度.注意:控制的图片为资源而不是背景,即 ...

  8. androidstudio图片居中_android imageview图片居中技巧应用

    做UI布局,尤其是遇到比较复杂的多重LinearLayout嵌套,常常会被一些比较小的问题困扰上半天,比如今天在使用ImageView的时候,想让其居中显示,可是无论怎样设置layout_gravit ...

  9. html悬浮的图片居中,HTML/CSS:图片居中(水平居中和垂直居中)

    css图片水平居中 1.利用margin: 0 auto实现图片水平居中 利用margin: 0 auto实现图片居中就是在图片上加上css样式margin: 0 auto 如下: 2.利用文本的水平 ...

最新文章

  1. Java 8 Stream Api 中的 map和 flatMap 操作
  2. Ubuntu环境搭建系列—JavaEE篇
  3. PAT甲级1087 All Roads Lead to Rome (30分):[C++题解]dijkstra求单源最短路综合、最短路条数、保存路径
  4. 【快乐水题】677. 键值映射
  5. 云小课 | MRS和自建Hadoop相比,有哪些优势?
  6. CSDN Markdown 文本居中、右对齐、左对齐
  7. c# winform 设置winform进入窗口后在文本框里的默认焦点
  8. 手机前端框架UI库(Frozen UI、WeUI、SUI Mobile)
  9. DEM数据下载、镶嵌等问题
  10. Base64基本原理及简单应用
  11. 高效人士睡觉前做的10件事
  12. 2021金山WPS秋招前端笔试题
  13. 相机XD卡格式化后,照片恢复
  14. 内存管理Memorynbsp;OC——第九天
  15. 基于PT8.2网关的二氧化碳监测及联动控制
  16. 免费截图工具PicPick 2.1.2绿色版
  17. 【网络原理】一个数据包从发送到接收在网络中经历了那些过程(详细分析)
  18. navicat误删了mysql数据库_navicat for mysql 误删数据库怎么恢复
  19. kafka监控api,手撕面试官
  20. 谷歌AI助NASA发现第二个太阳系;传快手完成新一轮融资;摩拜起诉小广告公司丨价值早报

热门文章

  1. 软件开发打败了80%的程序员
  2. 把感知机组装在一起就是神经网络了?
  3. 九问国产操作系统,九大掌门人万字回应!
  4. 每位开发者都应了解的数据库一致性!
  5. 「AI原生」时代来临?百度智能云提出AI-Native,发布新一代云基础架构「太行」
  6. 为什么开发者将迎来万亿美元黄金时代
  7. 加码 2000 亿新基建还不够,阿里云再放话:今年招 5000 人!
  8. AI 开发者不容错过的 20 个机器学习和数据科学网站
  9. 没能 PK 掉 WiFi 的 Li-Fi,可能是 5G 请来的救兵
  10. 为什么全栈开发对物联网至关重要?