`
dcj3sjt126com
  • 浏览: 1879053 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

IOS图片裁剪和小图看大图动画

    博客分类:
  • IOS
 
阅读更多

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过大和过小都会影响裁剪。

复制代码
 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 }
复制代码

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

复制代码
 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     return returnImage;
18 }
复制代码

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

 

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

复制代码
  1 //
  2 //  AvatarHDViewController.h
  3 //  CutPicTest
  4 //
  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 <QuartzCore/QuartzCore.h>
 12 
 13 #define SCREEN_WIDTH 320
 14 #define SCREEN_HEIGHT 480
 15 
 16 @interface AvatarHDViewController ()
 17 
 18 @end
 19 
 20 @implementation AvatarHDViewController
 21 @synthesize avatarImg;
 22 @synthesize beginRect;
 23 @synthesize delegate;
 24 
 25 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
 26 {
 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     return self;
 40 }
 41 
 42 - (void)viewDidLoad
 43 {
 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.delegate respondsToSelector:@selector(hiddenHDUserImg)]) {
112                     [self.delegate hiddenHDUserImg];
113                 }
114             }];
115 //        }
116 //    }];
117 }
118 
119 - (void)handleSwipeFromDownToUp{
120     //移除手势
121     for (UITapGestureRecognizer* recognizer in self.view.gestureRecognizers) {
122         if (recognizer==_recognizer) {
123             [self.view removeGestureRecognizer:recognizer];
124         }
125     }
126     [self exitAnimation];
127 }
128 
129 - (void)didReceiveMemoryWarning
130 {
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-图片裁剪框.zip

    在iOS开发中,图片裁剪是一项常见的功能,用于让用户按照特定需求选取图片的一部分。"ios-图片裁剪框.zip" 文件很可能包含了一个实现这一...通过学习和理解这个项目,开发者可以更好地掌握iOS中图片裁剪功能的实现。

    ios上的图片处理与动画代码

    在iOS平台上,图片处理和动画是开发者经常遇到的两个重要领域。这个代码示例主要涵盖了Quartz 2D和Core Animation这两个核心技术,它们是iOS图形渲染和动态效果的基础。 Quartz 2D是Apple提供的2D图形编程接口,它...

    ios应用源码之小图对大图切换效果 2018127

    总的来说,"ios应用源码之小图对大图切换效果"涉及到了iOS应用开发中的UI设计、手势识别、动画、Auto Layout等多个关键知识点。通过理解和掌握这些概念,开发者能够创建出更加互动和吸引人的用户界面。在实际项目中...

    iOS图片裁剪

    以上就是实现“iOS图片裁剪”功能的关键步骤和技术点。通过掌握这些,开发者可以创建出一个功能强大且用户体验良好的图片裁剪工具,类似于微信中的功能。在实际应用中,还需要考虑更多细节,如错误处理、界面设计...

    iOS点击查看大图,图片放大缩小

    "iOS点击查看大图,图片放大缩小"这个主题主要涉及到ScrollView和Image两类组件的使用,它们是iOS中实现图片查看功能的关键。 ScrollView是iOS SDK中的一个基础控件,用于展示可滚动的内容,它可以容纳比屏幕更大的...

    swift-ios仿微信和网易图片浏览器

    在iOS应用开发中,创建一个类似微信和网易的图片浏览器是一项常见的需求,它能提供良好的用户体验,让用户可以方便地查看和浏览多张图片。在这个项目中,我们将关注使用Swift进行图片处理和展示的关键技术。 首先,...

    ios-图片切换,点击缩放.zip

    例如,对于大图,可以使用UIImage的`initWithData:scale:`方法加载适当大小的图像,或者利用UIEdgeInsets来裁剪图片,只加载视图内需要的部分。同时,利用缓存策略可以减少重复加载,提高响应速度。 总结来说,"ios...

    ios应用源码之小图对大图:图片切换 2018127

    以上是对"ios应用源码之小图对大图:图片切换"这一知识点的详细解读,涉及到图片加载、显示、缩放、手势识别、动画过渡等多个方面。实际项目中,开发者需要结合具体需求,灵活运用这些技术来创建出满足用户体验的...

    ios-超简单实现图片剪辑.zip

    总结来说,"ios-超简单实现图片剪辑.zip"这个压缩包提供的示例应该包含了一个使用POP动画库和contentRect进行图片剪辑的iOS应用案例。它通过视图动画提高了用户交互性,并通过contentRect实现了图片的精确裁剪和拼接...

    ios-浏览大图,点击图片查看大图,再次点击还原原始尺寸.zip

    在iOS开发中,展示大图并支持用户点击...通过研究这个开源项目,开发者可以学习到如何在iOS应用中优雅地处理图片浏览功能,以及相关的动画和交互实现技巧。同时,这也是一个提升iOS开发技能和理解项目结构的好例子。

    ios图形动画处理

    在iOS开发中,图形与动画处理是至关重要的组成部分,它们为用户提供了丰富的视觉体验和流畅的操作感受。在本文中,我们将深入探讨标题“ios图形动画处理”所涵盖的知识点,包括UIFont、UIImage、UIColor等核心绘图类...

    ios-图片裁剪与3D旋转.zip

    3D旋转与图片裁剪功能,里面有详细的注释,看一遍就会了,

    ios应用源码之图片倒影 2018127

    在iOS应用开发中,创建图片倒影是一种常见的视觉效果,可以增强用户...总之,图片倒影的实现涉及到iOS图形和动画的核心知识,是iOS开发者必须掌握的技能之一。通过实践和学习,你可以创造出更加引人入胜的用户体验。

    ios应用源码之简单的图片放大缩小demouitestapp 2018128

    8. **响应式编程**: 这个应用可能采用了响应式编程框架如ReactiveCocoa或RxSwift,将手势事件、动画和界面更新结合在一起,使得代码更加简洁和可维护。 综上所述,这个源码实例涵盖了iOS应用开发中处理图片的关键...

    ios-图片选择器.zip

    此外,对大图的压缩和解码策略也是性能优化的重要环节。 8. **国际化与适配**: 图片选择器中的文字和布局应支持多种语言和屏幕尺寸,这涉及到本地化设置和Auto Layout的应用。CXXChooseImage可能包含了相应的适配...

    ios 图片浏览 仿系统相册图片浏览

    综上所述,"GooglyPuff-Final"项目应该是一个实现上述功能的iOS图片浏览组件,它可能包括自定义的`UICollectionViewCell`、图片加载策略、手势识别机制以及用户界面元素。通过研究和学习这个项目,开发者可以更好地...

    ios应用源码之图片区域截取demo 2018127

    在iOS应用开发中,图片区域截取是一项常见的需求,它涉及到图像处理和用户交互。本示例代码"ios应用源码之图片区域截取demo 2018127"提供了一个完整的解决方案,帮助开发者了解如何在iOS应用中实现自定义的截图功能...

    ios应用源码之酷炫的图片展示效果 20181210

    在iOS应用开发中,酷炫的图片展示效果是吸引用户注意力和提升用户体验的重要手段。本文将深入探讨如何利用iOS的SDK和编程技术实现这样的效果,主要关注以下知识点: 1. **UIImageView**: `UIImageView`是iOS中用于...

    iOS图片异步加载SDWebImage

    3. **图片处理**:SDWebImage支持图片的缩放、裁剪等操作,可以减少内存消耗,防止大图加载导致的问题。 4. **占位图与加载动画**:在图片下载期间,可以设置占位图以提供视觉反馈,同时,SDWebImage还支持自定义...

    (IOS开发)自选图片拼图源码

    这涉及到图片的裁剪和保存,可以使用Core Graphics或者第三方库如UIImage+CropScale进行操作。 3. **数据结构**:为了存储拼图的原始状态和当前状态,开发者可能会使用数组或矩阵来表示各个拼图块的位置。这需要...

Global site tag (gtag.js) - Google Analytics