IOS 照片编辑的view封装的实例详解
程序员文章站
2023-12-21 12:23:34
ios 照片编辑的view封装
该控件有旋转,缩放,拖动,剪裁的功能,封装成了一个imagecropperview类
需要导入的库:quartzcore.framewo...
ios 照片编辑的view封装
该控件有旋转,缩放,拖动,剪裁的功能,封装成了一个imagecropperview类
需要导入的库:quartzcore.framework
imagecopperview.h
#import <uikit/uikit.h> @protocol imagecropperdelegate; @interface imagecropperview : uiview { uiimageview *imageview; id <imagecropperdelegate> delegate; } @property (nonatomic, retain) uiimage *image; @property (nonatomic, retain) uiimage *croppedimage; @property (nonatomic, assign) id <imagecropperdelegate> delegate; @property (nonatomic, assign) bool enable; @property (nonatomic, assign) bool ispaning; - (void)setup; - (void)finishcropping; - (void)reset; @end @protocol imagecropperdelegate <nsobject> - (void)changemovestatewithcropper:(uipangesturerecognizer*)gesture crop:(imagecropperview*)imagecrop; @end
imagecopperview.m
#import "imagecropperview.h" #import <quartzcore/quartzcore.h> #include <math.h> #import "uiimage+rotation.h" @interface imagecropperview() { @private cgsize _originalimageviewsize; } @property (nonatomic, retain) uiimageview *imageview; @end @implementation imagecropperview @synthesize imageview, image = _image, delegate, croppedimage; - (void)setup { _enable = yes; self.clipstobounds = yes; self.backgroundcolor = [uicolor clearcolor]; self.imageview = [[[uiimageview alloc] initwithframe:cgrectmake(0.0, 0.0, self.frame.size.width, self.frame.size.height)] autorelease]; imageview.userinteractionenabled = yes; [self addsubview:imageview]; uirotationgesturerecognizer *rotateges = [[uirotationgesturerecognizer alloc] initwithtarget:self action:@selector(rotateimage:)]; [imageview addgesturerecognizer:rotateges]; [rotateges release]; uipinchgesturerecognizer *scaleges = [[uipinchgesturerecognizer alloc] initwithtarget:self action:@selector(scaleimage:)]; [imageview addgesturerecognizer:scaleges]; [scaleges release]; uipangesturerecognizer *moveges = [[uipangesturerecognizer alloc] initwithtarget:self action:@selector(moveimage:)]; [moveges setminimumnumberoftouches:1]; [moveges setmaximumnumberoftouches:1]; [imageview addgesturerecognizer:moveges]; [moveges release]; } - (id)initwithframe:(cgrect)frame { self = [super initwithframe:frame]; if (self) { self.frame = frame; [self setup]; } return self; } float _lasttransx = 0.0, _lasttransy = 0.0; - (void)moveimage:(uipangesturerecognizer *)sender { _ispaning = yes; if (delegate&&[delegate respondstoselector:@selector(changemovestatewithcropper:crop:)]) { [delegate changemovestatewithcropper:sender crop:self]; }else{ return; } if (sender.numberoftouches != 1||_enable == no) { return; } //获取在视图中手势的触点位置 cgpoint translatedpoint = [sender translationinview:self]; if([sender state] == uigesturerecognizerstatebegan) { _lasttransx = 0.0; _lasttransy = 0.0; } cgaffinetransform trans = cgaffinetransformmaketranslation(translatedpoint.x - _lasttransx, translatedpoint.y - _lasttransy); //cgaffinetransformconcat将imageview.transform和trans两个动画连续起来 cgaffinetransform newtransform = cgaffinetransformconcat(imageview.transform, trans); _lasttransx = translatedpoint.x; _lasttransy = translatedpoint.y; nslog(@"_lasttransx==%f,_lasttransy==%f",_lasttransx,_lasttransy); imageview.transform = newtransform; } float _lastscale = 1.0; - (void)scaleimage:(uipinchgesturerecognizer *)sender { _ispaning = no; if (sender.numberoftouches != 2||_enable == no) { return; } if([sender state] == uigesturerecognizerstatebegan) { _lastscale = 1.0; return; } cgfloat scale = [sender scale]/_lastscale; cgaffinetransform currenttransform = imageview.transform; cgaffinetransform newtransform = cgaffinetransformscale(currenttransform, scale, scale); [imageview settransform:newtransform]; _lastscale = [sender scale]; } float _lastrotation = 0.0; - (void)rotateimage:(uirotationgesturerecognizer *)sender { _ispaning = no; if (sender.numberoftouches != 2||_enable == no) { return; } if([sender state] == uigesturerecognizerstateended) { _lastrotation = 0.0; return; } cgfloat rotation = -_lastrotation + [sender rotation]; cgaffinetransform currenttransform = imageview.transform; cgaffinetransform newtransform = cgaffinetransformrotate(currenttransform,rotation); [imageview settransform:newtransform]; _lastrotation = [sender rotation]; } - (void)setimage:(uiimage *)image { if (_image != image) { _image = [image retain]; } float _imagescale = self.frame.size.width / image.size.width; self.imageview.frame = cgrectmake(0, 0, image.size.width*_imagescale, image.size.height*_imagescale); _originalimageviewsize = cgsizemake(image.size.width*_imagescale, image.size.height*_imagescale); imageview.image = image; imageview.center = cgpointmake(self.frame.size.width/2.0, self.frame.size.height/2.0); } - (void)finishcropping { float zoomscale = [[self.imageview.layer valueforkeypath:@"transform.scale.x"] floatvalue]; float rotate = [[self.imageview.layer valueforkeypath:@"transform.rotation.z"] floatvalue]; float _imagescale = _image.size.width/_originalimageviewsize.width; cgsize cropsize = cgsizemake(self.frame.size.width/zoomscale, self.frame.size.height/zoomscale); cgpoint croppervieworigin = cgpointmake((0.0 - self.imageview.frame.origin.x)/zoomscale, (0.0 - self.imageview.frame.origin.y)/zoomscale); if((nsinteger)cropsize.width % 2 == 1) { cropsize.width = ceil(cropsize.width); } if((nsinteger)cropsize.height % 2 == 1) { cropsize.height = ceil(cropsize.height); } cgrect croprectinimage = cgrectmake((nsinteger)(croppervieworigin.x*_imagescale) ,(nsinteger)( croppervieworigin.y*_imagescale), (nsinteger)(cropsize.width*_imagescale),(nsinteger)(cropsize.height*_imagescale)); uiimage *rotinputimage = [self.image imagerotatedbyradians:rotate]; cgimageref tmp = cgimagecreatewithimageinrect([rotinputimage cgimage], croprectinimage); self.croppedimage = [uiimage imagewithcgimage:tmp scale:self.image.scale orientation:self.image.imageorientation]; cgimagerelease(tmp); } - (void)reset { self.imageview.transform = cgaffinetransformidentity; } - (void)dealloc { self.image = nil; self.croppedimage = nil; self.imageview = nil; [super dealloc]; } @end
对uiimage添加了一个category
uiimage+rotation.h
#import <uikit/uikit.h> @interface uiimage (rotation) - (uiimage *)imagerotatedbyradians:(cgfloat)radians; - (uiimage *)imagerotatedbydegrees:(cgfloat)degrees; @end
uiimage+rotation.m
#import "uiimage+rotation.h" /************ 角度=弧度/pi*180 弧度=角度/180*pi *************/ cgfloat degreestoradians(cgfloat degrees) {return degrees * m_pi / 180;}; cgfloat radianstodegrees(cgfloat radians) {return radians * 180/m_pi;}; @implementation uiimage (rotation) - (uiimage *)imagerotatedbyradians:(cgfloat)radians { return [self imagerotatedbydegrees:radianstodegrees(radians)]; } - (uiimage *)imagerotatedbydegrees:(cgfloat)degrees { /***** cgaffinetransformmakerotation 通过指定角度来创建一个旋转矩阵 cgaffinetransformrotate 在已存在的矩阵中使用旋转 *****/ uiview *rotatedviewbox = [[uiview alloc] initwithframe:cgrectmake(0,0,self.size.width, self.size.height)]; cgaffinetransform t = cgaffinetransformmakerotation(degreestoradians(degrees)); //给view旋转角度 rotatedviewbox.transform = t; cgsize rotatedsize = rotatedviewbox.frame.size; [rotatedviewbox release]; //开始编辑图形上下文 uigraphicsbeginimagecontext(rotatedsize); //定义一个图形上下文 cgcontextref bitmap = uigraphicsgetcurrentcontext(); //沿x轴移动rotatedsize.width/2,y轴移动rotatedsize.height cgcontexttranslatectm(bitmap, rotatedsize.width/2, rotatedsize.height/2); //以原点(左下角)为中心旋转degreestoradians(degrees)弧度,正角度逆时针,负角度顺时针 cgcontextrotatectm(bitmap, degreestoradians(degrees)); //缩放x轴,y轴方向 cgcontextscalectm(bitmap, 1.0, -1.0); //绘制位图 cgcontextdrawimage(bitmap, cgrectmake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self cgimage]); //赋值给uiimage uiimage *resimage = uigraphicsgetimagefromcurrentimagecontext(); //结束绘制 uigraphicsendimagecontext(); return resimage; } @end;
viewcontroller.m
#import "viewcontroller.h" #import <quartzcore/quartzcore.h> #import "imagecropperview.h" @interface viewcontroller ()<imagecropperdelegate>{ } @property (nonatomic, retain) iboutlet imagecropperview *cropper; @property (nonatomic, retain) iboutlet uiimageview *result; @property (retain, nonatomic) iboutlet uiimageview *resultsecond; @property (nonatomic, retain) iboutlet uibutton *btn; @property (retain, nonatomic) iboutlet imagecropperview *croppersecond; @property (retain, nonatomic) iboutlet uibutton *cropbutton; @end @implementation viewcontroller //@synthesize cropper, result, btn; - (void)viewdidload { [super viewdidload]; // do any additional setup after loading the view, typically from a nib. _cropper.layer.borderwidth = 1.0; _cropper.layer.bordercolor = [uicolor bluecolor].cgcolor; _cropper.delegate = self; [_cropper setup]; _cropper.image = [uiimage imagenamed:@"2.jpg"]; [_btn addtarget:self action:@selector(buttonclicked) forcontrolevents:uicontroleventtouchupinside]; _croppersecond.layer.bordercolor = [uicolor blackcolor].cgcolor; _croppersecond.layer.borderwidth = 2.0; _croppersecond.delegate = self; [_croppersecond setup]; _croppersecond.image = [uiimage imagenamed:@"1.jpg"]; [_cropbutton addtarget:self action:@selector(tapcropbutton) forcontrolevents:uicontroleventtouchupinside]; } - (void)buttonclicked { if ([_btn.currenttitle isequaltostring:@"crop1"]) { [_cropper finishcropping];//保存 _result.image = _cropper.croppedimage; _cropper.hidden = yes; [_btn settitle:@"back" forstate:uicontrolstatenormal]; [_btn settitle:@"back" forstate:uicontrolstatehighlighted]; }else { [_cropper reset]; _cropper.hidden = no; [_btn settitle:@"crop1" forstate:uicontrolstatenormal]; [_btn settitle:@"crop1" forstate:uicontrolstatehighlighted]; _result.image = nil; } _croppersecond.enable = yes; _cropper.enable = yes; } - (void)tapcropbutton{ if ([_cropbutton.currenttitle isequaltostring:@"crop2"]) { [_croppersecond finishcropping]; _croppersecond.enable = no; _resultsecond.image = _croppersecond.croppedimage; _croppersecond.hidden = yes; [_cropbutton settitle:@"back" forstate:uicontrolstatenormal]; [_cropbutton settitle:@"back" forstate:uicontrolstatehighlighted]; }else { [_croppersecond reset]; _croppersecond.hidden = no; [_cropbutton settitle:@"crop2" forstate:uicontrolstatenormal]; [_cropbutton settitle:@"crop2" forstate:uicontrolstatehighlighted]; _resultsecond.image = nil; } _croppersecond.enable = yes; _cropper.enable = yes; } #pragma mark - imagecropperdelegate - (void)changemovestatewithcropper:(uipangesturerecognizer*)gesture crop:(imagecropperview*)imagecrop{ if (gesture.state == uigesturerecognizerstateended) { nslog(@"点击编辑器结束,两个_cropper都可以进行编辑"); _croppersecond.enable = yes; _cropper.enable = yes; } } - (void)touchesbegan:(nsset*)touches withevent:(uievent*)event; { //判断点击在控件上 uitouch *touch = [touches anyobject]; if ([_cropper pointinside:[touch locationinview:_cropper] withevent:nil]) { nslog(@"_cropper1 被触摸,禁用_cropper2"); _croppersecond.enable = no; }else if ([_croppersecond pointinside:[touch locationinview:_croppersecond] withevent:nil]){ nslog(@"_cropper2 被触摸,禁用_cropper1"); _cropper.enable = no; } } - (void)dealloc { [_croppersecond release]; [_cropbutton release]; [_resultsecond release]; [super dealloc]; } - (void)viewdidunload { [self setcroppersecond:nil]; [self setcropbutton:nil]; [self setresultsecond:nil]; [super viewdidunload]; } @end
截图:
最后要注意,因为我是用xib做的,拖上去的uiview要将其class改成imagecropperview
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!