前言:本来只是想实现一个简单的截图功能的,后来又想做的更好一点,就加上了虚线框。要实现截图本身是很容易的,只需要CGImageCreateWithImageInRect:这一个方法即可。后来加了虚线框就复杂了很多,因为还要让虚线框适时的消失。
现附上最终实现的效果:
截图后,点击segControl,虚线框会消失;点击屏幕的任何地方,虚线框和segControl都会消失。除了界面有点丑外,算是基本实现了预期效果。
正文:
我们希望的是:当手指在屏幕上移动时,虚线框随着手指的移动而生成。两个关键问题:手指移动时怎么触发画图机制?怎么绘制虚线框?
一、手指移动的检测
不需要在@interface中继承什么,直接在.m文件中,实现以下几个方法即可。他们都是UIResponder的方法。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
当手指开始移动时,系统自动调用touchesBegan; 在手指移动过程中,touchesMoved; 手指移动结束,touchesEnded; 当有外来事件,如打入电话,touchesCancelled。
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touchesBegan"); _isMoved = false;//在本程序中,设置这个参数的目的是为了让虚线框适时消失 _touch = [[touches anyObject]retain]; startPoint = [_touch locationInView:self];//记录起始点,point是声明为全局变量 [_segControl removeFromSuperview]; [self setNeedsDisplay]; //重绘界面,目的在于让虚线框消失 } //手指移动过程 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touchesMoved"); _isMoved = true; endPoint=[_touch locationInView:self];//记录结束点的坐标 // 用结束点的坐标减去起始点的坐标我么得到一个矩形框的宽和高,声明一个点记录一下; finalPoint.x=endPoint.x-startPoint.x; finalPoint.y=endPoint.y-startPoint.y; // 调用重绘方法,setNeedsDisplay中会自动调用drawRect:,我们不能自己调用drawRect: [self setNeedsDisplay]; } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touchesEnded"); endPoint = [_touch locationInView:self];//记录起始点,point是声明为全局变量 if(_isMoved){ _segControl.frame = CGRectMake(endPoint.x-50,endPoint.y+5,100,35); [self addSubview:_segControl]; } _isMoved = false; [_touch release]; } //当接收到系统中断时,这些方法都不是自己调用的 -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touchesCancelled"); }
二、虚线框的绘制
上面的代码中,我们在两个地方都调用了这样一个方法:[self setNeedsDisplay],这是UIView提供的方法,表示需要开始重绘界面。它还有个类似的,叫setNeedsDisplayInRect,表示在一个矩形区域内重绘界面。
这个方法的具体实现我们是不知道的,但我们知道的是,这个方法会自动调用drawRect:方法,界面重绘的具体操作都是在drawRect:中进行的。
所以,我们要自己绘制界面必须调用setNeedsDisplay方法,并重写drawRect方法。
//准备工作做好后,我们就要画虚线的矩形框了.我们需要重写drawRect方法。完整代码如下: - (void)drawRect:(CGRect)rect//这个rect参数是这个view在一个cotroller中的位置 { NSLog(@"drawRect called ,%f %f %f %f",rect.origin.x,rect.origin.y,rect.size.width,rect.size.height); if(_isMoved == true){ //获取绘图上下文-画板 CGContextRef ref=UIGraphicsGetCurrentContext(); //设置虚线 float lengths[] = {10,10}; CGContextSetLineDash(ref,2, lengths, 1); //画截取线框 CGContextAddRect(ref,CGRectMake(startPoint.x,startPoint.y,finalPoint.x,finalPoint.y)); //设置颜色 CGContextSetStrokeColorWithColor(ref,[UIColor redColor].CGColor); //设置线宽 CGContextSetLineWidth(ref,3); CGContextStrokePath(ref); }
在touchesMoved中,我将_isMoved设为true,重绘界面时,会画出矩形框;
在touchesEnd中,将_isMoved设为false,那么它调用的重绘界面,就不会画矩形框,实现了矩形框的消失。
三、区域截图
这个实在是没有什么好讲的,直接附代码
//截取图片 -(UIImage *)cutImageFromOrignalImage { CGRect rect = CGRectMake(startPoint.x,startPoint.y,finalPoint.x,finalPoint.y); CGImageRef imgRef = CGImageCreateWithImageInRect([_orignalImage CGImage], rect); UIImage *img = [UIImage imageWithCGImage:imgRef]; return img; }
四、特别注意
这个程序也算基本完成了。但是,有一点要注意,那就是这个上面显示的image,是怎么加上去的。
一般情况下,我们都是直接用imageView.image = img,把图片添加进来,但是在这种需要在界面上绘图的情况,这种加图片的方法就不行了,不是加不上去,而是画不上矩形框,必须把这个img设为背景:
self.backgroundColor = [UIColor colorWithPatternImage:_orignalImage];
这个现象很奇怪,手指移动都能检测,也能触发绘图,segcontrol也能显示,但就是画不上矩形框。
分析:在网上查了一下,貌似是drawRect:方法不能在UIImageView上画图。很奇怪哈,UIImageView继承自UIView,为什么不能再上面画图了?苹果官方文档上是这么说的:UIImageView是专门为显示图片做的控件,用了最优显示技术,是不让调用darwrect方法的, 要调用这个方法,只能从UIView里重写。
但我之前猜测以为可能是图层layer问题吧,就查了下,发觉这块也有很多东西应该学习。
可以考虑看一下 CALayer和UIView 这2者的联系和区别,到时候可参考这篇博客http://www.cnblogs.com/lovecode/articles/2249548.html