首先说明一下要求,知道了要求之后才能更好地工作呢。
1、通过滑动滑块来修改画笔的粗细;最小值为4,最大值为15;UISlider;
2、点击撤销按钮后,绘图区域撤销上一次画线操作;
3、点击保存按钮后,将绘图区域的图片按照顺序保存到上方的视图中;UIImageView;
4、保存的图片大于6张后,继续从第一个视图按照顺序往下保存;
5、每次点击按钮后,还要将绘制的图片保存到iOS相册内; 可以通过UIImageWriteToPhotosAlbum函数保存到图片相册,保存成功后可以在iPhone模拟器的照片应用程序中查看
首先创建工程,single view Application
先说说思路:
1.将界面给布置好,图片1——6的位置为UIImageView,"撤销"“保存",是两个UIButton,中间是一个UISlider,下面绘图区是一个UIView
2.当点击保存的时候,会弹出对话框,提示是否进行保存,如果保存就将绘图区的图片保存到上面同时保存的本地的照片库中,如果点击取消,则不进行保存
3.写保存,撤销按钮点击事件,(NSLog(@"hello");)进行界面测试
4.对绘图区进行书写,进行绘图。
5.绘图区应该是在外面是一个自己创建的继承与UIView的View
6.在绘图区的操作:
6.1.重写
- (void)drawRect:(CGRect)rect;方法
首先是重写父视图的drawRect:rect方法;
6.2.添加
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;方法
6.3.添加
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;方法
6.4.将每一次画得图保存为一个image,添加方法
- (UIImage *)getImageFromCurrentContext;即得到当前视图的截图
6.5.
画图过程应该是:每一次触摸屏幕的开始,就是一个触摸路径的开始,然后开始绘制,在绘制的过程中,只要绘制就会调用touchesMoved:方法
,同时对图片进行调用[self setNeedsDisplayInrect:rect];程序就会跳转到drawRect:方法中,对图片进行绘制。
根据上面的思路,来进行工作的实施。
首先是界面:
在viewController.m 文件中书写代码:
#import "ViewController.h" #import "CustomView.h" #import "CustomManager.h" #import "CustomPath.h" @interface ViewController () { NSInteger imageCount; } @end @implementation ViewController #pragma mark---------------------------------------viewDidLoad - (void)viewDidLoad { [super viewDidLoad]; //后面的白板容器视图 imageCount = 0; UIView * containerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)]; containerView.backgroundColor = [UIColor whiteColor]; containerView.tag = 0; [self.view addSubview:containerView]; //上面的文字视图 UIView * titleView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 64)]; [containerView addSubview:titleView]; //保存和撤销按钮 UIButton * cancelButton = [[UIButton alloc]initWithFrame:CGRectMake(10, 0, 50, 40)]; [cancelButton setTitle:@"撤销" forState:UIControlStateNormal]; [cancelButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [cancelButton addTarget:self action:@selector(didClickCancelButton:) forControlEvents:UIControlEventTouchUpInside]; cancelButton.backgroundColor = [UIColor grayColor]; UIButton * saveButton = [[UIButton alloc]initWithFrame:CGRectMake(260, 0, 50, 40)]; [saveButton setTitle:@"保存" forState:UIControlStateNormal]; [saveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [saveButton addTarget:self action:@selector(didClickSaveButton:) forControlEvents:UIControlEventTouchUpInside]; saveButton.backgroundColor = [UIColor grayColor]; [containerView addSubview:cancelButton]; [containerView addSubview:saveButton]; //添加划线空间 UISlider * slider = [[UISlider alloc]initWithFrame:CGRectMake(70, 0, 150, 0)]; [titleView addSubview:slider]; slider.minimumValue = 4.0f; slider.maximumValue = 15.0f; [slider addTarget:self action:@selector(changeSliderValue:) forControlEvents:UIControlEventValueChanged]; //添加6个UIImageView UIView * sixContainerView = [[UIView alloc]initWithFrame:CGRectMake(0, 50, 320, 215)]; sixContainerView.backgroundColor = [UIColor greenColor]; sixContainerView.tag = 3; [containerView addSubview:sixContainerView]; UIImageView * firstImage = [[UIImageView alloc]initWithFrame:CGRectMake(5, 5, 100, 100)]; UIImageView * secondImage = [[UIImageView alloc]initWithFrame:CGRectMake(110, 5, 100, 100)]; UIImageView * thirdImage = [[UIImageView alloc]initWithFrame:CGRectMake(215, 5, 100, 100)]; UIImageView * forthImage = [[UIImageView alloc]initWithFrame:CGRectMake(5, 110, 100, 100)]; UIImageView * fifthImage = [[UIImageView alloc]initWithFrame:CGRectMake(110, 110, 100, 100)]; UIImageView * sixthImage = [[UIImageView alloc]initWithFrame:CGRectMake(215, 110, 100, 100)]; firstImage.backgroundColor = [UIColor grayColor]; secondImage.backgroundColor = [UIColor grayColor]; [thirdImage setBackgroundColor:[UIColor grayColor]]; forthImage.backgroundColor = [UIColor grayColor]; fifthImage.backgroundColor = [UIColor grayColor]; sixthImage.backgroundColor = [UIColor grayColor]; firstImage.tag = 1001; secondImage.tag = 1002; thirdImage .tag = 1003; forthImage.tag = 1004; fifthImage .tag = 1005; sixthImage.tag = 1006; firstImage.userInteractionEnabled = YES; secondImage.userInteractionEnabled = YES; thirdImage.userInteractionEnabled = YES; forthImage.userInteractionEnabled = YES; fifthImage.userInteractionEnabled = YES; sixthImage.userInteractionEnabled = YES; [firstImage clearsContextBeforeDrawing]; [sixContainerView addSubview:firstImage]; [sixContainerView addSubview:secondImage]; [sixContainerView addSubview:thirdImage]; [sixContainerView addSubview:forthImage]; [sixContainerView addSubview:fifthImage]; [sixContainerView addSubview: sixthImage]; //添加颜色选择 UIButton * redButton = [[UIButton alloc]initWithFrame:CGRectMake(30, 270, 25, 10)]; redButton.backgroundColor = [UIColor redColor]; [redButton addTarget:self action:@selector(didClickRedButton:) forControlEvents:UIControlEventTouchUpInside]; UIButton * greenButton = [[UIButton alloc]initWithFrame:CGRectMake(150, 270, 25, 10)]; [greenButton setBackgroundColor:[UIColor greenColor]]; [greenButton addTarget:self action:@selector(didClickGreenButton:) forControlEvents:UIControlEventTouchUpInside]; UIButton * blueButton = [[UIButton alloc]initWithFrame:CGRectMake(260, 270, 25, 10)]; blueButton.backgroundColor = [UIColor blueColor]; [blueButton addTarget:self action:@selector(didClickBlueButton:) forControlEvents:UIControlEventTouchUpInside]; [containerView addSubview:redButton]; [containerView addSubview:greenButton]; [containerView addSubview:blueButton]; //添加画板视图 CustomView * cView = [[CustomView alloc]initWithFrame:CGRectMake(5, 280, 310, 210)]; cView.backgroundColor= [UIColor grayColor]; cView.tag = 1; [containerView addSubview:cView]; }
当点击保存按钮和撤销按钮,进行相应地事件的触发,当跳出一个提示框后进行的操作:
#pragma mark---------------------------------------alertView - (void)alertView:(UIAlertView *)alertViewt clickedButtonAtIndex:(NSInteger)buttonIndex { UIView * containerView = [self.view viewWithTag:0]; CustomView * cView = (CustomView *) [containerView viewWithTag:1]; NSMutableArray * pathListArray = [CustomManager defaultManager].pathList; UIView * sixContainerView = [containerView viewWithTag:3]; NSArray * array = [sixContainerView subviews]; UIImage * tempImage = [cView getImageFromCurrentContext]; switch (buttonIndex) { case 0: { [pathListArray removeAllObjects]; [cView setNeedsDisplay]; } NSLog(@"取消"); break; case 1: { UIImageWriteToSavedPhotosAlbum(tempImage, NULL, NULL, NULL); imageCount++; switch (imageCount) { case 1: ((UIImageView *)array[0]).image = tempImage; break; case 2: ((UIImageView *)array[1]).image = tempImage; break; case 3: ((UIImageView *)array[2]).image = tempImage; break; case 4: ((UIImageView *)array[3]).image = tempImage; break; case 5: ((UIImageView *)array[4]).image = tempImage; break; case 6: ((UIImageView *)array[5]).image = tempImage; break; default: break; } [pathListArray removeAllObjects]; [cView setNeedsDisplay]; } NSLog(@"确定"); break; } } #pragma mark---------------------------------------changeSliderValue: - (void) changeSliderValue:(UISlider *)sender { UIView * containerView = [self.view viewWithTag:0]; CustomView * cView = (CustomView *)[containerView viewWithTag:1]; cView.lineWidth = sender.value; NSLog(@"%f",sender.value); } #pragma mark---------------------------------------didClickSaveButton: - (void) didClickSaveButton:(UIButton *)sender { if (imageCount > 5) { imageCount = 0; } UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"是否保存" message:@"要保存吗?" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; [alert show]; NSLog(@"save click"); } #pragma mark---------------------------------------didClickCancelButton: - (void) didClickCancelButton:(UIButton *)sender { UIView * containerView = [self.view viewWithTag:0]; CustomView * cView = (CustomView *) [containerView viewWithTag:1]; NSMutableArray * pathListArray = [CustomManager defaultManager].pathList; [pathListArray removeLastObject]; [cView setNeedsDisplay]; NSLog(@"cancel click"); } #pragma mark---------------------------------------didClickBlueButton: - (void) didClickBlueButton:(UIButton *)sender { UIView * containerView = [self.view viewWithTag:0]; CustomView * cView = (CustomView *) [containerView viewWithTag:1]; cView.lineColor = [UIColor blueColor]; NSLog(@"blue"); } #pragma mark---------------------------------------didClickRedButton: - (void) didClickRedButton:(UIButton *)sender { UIView * containerView = [self.view viewWithTag:0]; CustomView * cView = (CustomView *) [containerView viewWithTag:1]; cView.lineColor = [UIColor redColor]; NSLog(@"red"); } #pragma mark---------------------------------------didClickGreenButton: - (void) didClickGreenButton:(UIButton *)sender { UIView * containerView = [self.view viewWithTag:0]; CustomView * cView = (CustomView *) [containerView viewWithTag:1]; cView.lineColor = [UIColor greenColor]; NSLog(@"green"); } #pragma mark---------------------------------------didReceiveMemoryWarning - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } @end
创建一个单例:用来存储每一条路径的信息。一个数组。这个数组中得元素是一个另外一个类的每一个对象,另外一个类是linpath类。
在这个类中保存着每一个对象的所有数据,(线的路径,线的宽度,线的颜色)。
然后再drawRect:方法中for (in)这个单例中那个数组的所有元素,遍历出后,进行绘画和渲染。
在这里,我们分别实现各个方法,
首先创建一个CustomView,用来进行绘图:绘图代码:
首先是CustomView.h文件中得声明:
#import <UIKit/UIKit.h> @interface CustomView : UIView @property (nonatomic,retain) UIColor* lineColor; - (CGMutablePathRef) pathFromPoint:(CGPoint)originPoint toPoint:(CGPoint) finalPoint; - (UIImage *)getImageFromCurrentContext; @property (nonatomic,assign)float lineWidth; @end
然后是CustomView.m文件中各个方法的实现。
#import "CustomView.h" #import "CustomManager.h" #import "CustomPath.h" //添加自定义视图的延展... @interface CustomView () //获取坐标内的路径... //- (CGMutablePathRef) pathFromPoint:(CGPoint)originPoint toPoint:(CGPoint) finalPoint; //- (UIImage *)getImageFromCurrentContext; @end //静态内联函数 //程序启动后,这种类型的函数就已经准备完毕,在代码区准备程序内调用 static inline CGPoint midPoint(CGPoint point1,CGPoint point2) { CGFloat minX = (point1.x + point2.x)/2.0f; CGFloat minY = (point2.y + point2.y)/2.0f; return CGPointMake(minX, minY); } @implementation CustomView { //添加私有地实例变量 //启动点... CGPoint startPoint; //结束点... CGPoint endPoint; //控制点 CGPoint controlPoint; UIImage *tempImage; //声明路径私有地中间变量 CGMutablePathRef tempPath; //声明每一次触摸完成后的路径 CGMutablePathRef touchPath; //声明全部路径变量,用来存储所有的中间路径..... CGMutablePathRef totalPath; } #pragma mark---------------------------------------初始化 - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { startPoint = CGPointZero; endPoint = CGPointZero; controlPoint = CGPointZero; //创建全部路径对象存储空间 // totalPath = CGPathCreateMutable(); _lineColor = [UIColor whiteColor]; } return self; } #pragma mark---------------------------------------开始画 drawRect: - (void)drawRect:(CGRect)rect { //通知父类,开始画图.... [super drawRect:rect]; //如果两个都是(0,0),则不画图... if (CGPointEqualToPoint(startPoint, CGPointZero) && CGPointEqualToPoint(endPoint,CGPointZero)) { return; } //1.获取当前画布... CGContextRef context = UIGraphicsGetCurrentContext();//context 就是传过来的rect NSMutableArray * pathListArray = [CustomManager defaultManager].pathList; for (CustomPath * itemPath in pathListArray) { CGContextSetLineCap(context, kCGLineCapRound); CGContextSetLineWidth(context, itemPath.lineWidth); CGContextSetStrokeColorWithColor(context, itemPath.lineColor); CGContextAddPath(context, itemPath.linePath); CGContextStrokePath(context); } /**/ //1.开始创建图片画布 /**/ } #pragma mark---------------------------------------touchBegan - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //每一次触摸屏幕的开始,就是一个触摸路径的开始..... touchPath = CGPathCreateMutable(); CustomPath * itemPath = [[CustomPath alloc]init]; itemPath.lineWidth =_lineWidth; itemPath .lineColor = _lineColor.CGColor; itemPath.linePath = touchPath; [[CustomManager defaultManager].pathList addObject:itemPath]; //获取触摸对象 UITouch * touch = [touches anyObject]; //设置每次触摸的点 startPoint = [touch previousLocationInView:self]; endPoint = [touch previousLocationInView:self]; controlPoint =[touch previousLocationInView:self]; [self touchesMoved:touches withEvent:event]; } #pragma mark---------------------------------------touchesMoved //当手指开始触摸得时候,实现的方法... - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { //获取当前的触摸对象 UITouch * touch = [touches anyObject]; //设置起点 startPoint = controlPoint; //设置控制点为前一个触摸点 controlPoint = [touch previousLocationInView:self]; //设置中点为当前触摸点 endPoint = [touch locationInView:self]; //生成截图图片对象... // tempImage = [self getImageFromCurrentContext]; CGPoint mid1 = midPoint(startPoint,controlPoint); CGPoint mid2 = midPoint(controlPoint, endPoint); //获取当前应该绘制的路径 tempPath = [self pathFromPoint:mid1 toPoint:mid2]; //获取最小的能够容纳路径的矩形体积 CGRect rect = CGPathGetBoundingBox(tempPath); rect.origin.x -=15.0f; rect.origin.y -=15.0f; rect.size.height +=30.0f; rect.size.width +=30.0f; //将中间变量tempPath添加到全部路径 // CGPathAddPath(totalPath, NULL, tempPath); //将中间变量tempPath添加到每一个的触摸路径touchPath内 CGPathAddPath(touchPath, NULL, tempPath); //修改最后的自定义的path对象 CustomPath * itemPath = [[CustomManager defaultManager].pathList lastObject]; itemPath.linePath = touchPath; //这里的self是实例对象 [self setNeedsDisplayInRect:rect]; } #pragma mark---------------------------------------touchesEnded //当手指结束触摸时,触发的方法 - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { CustomPath * itemPath = [[CustomPath alloc]init]; itemPath.linePath = touchPath; } //获取当前视图的截图.... #pragma mark---------------------------------------画图 - (UIImage *)getImageFromCurrentContext { //1.开始创建图片画布 UIGraphicsBeginImageContext(self.bounds.size); //2.将视图的内容渲染到图片画布上 [self.layer renderInContext:UIGraphicsGetCurrentContext()]; //3.通过图片画布获取当前画布... UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); //4.结束图片画布 UIGraphicsEndImageContext(); return result; } #pragma mark---------------------------------------获取坐标内路径 //获取坐标内的路径... - (CGMutablePathRef) pathFromPoint:(CGPoint)originPoint toPoint:(CGPoint) finalPoint { //创建块 CGMutablePathRef path = CGPathCreateMutable(); //移动到出发点 CGPathMoveToPoint(path, NULL, originPoint.x, originPoint.y); //添加直线结束点 // CGPathAddLineToPoint(path,NULL , finalPoint.x, finalPoint.y); //添加曲线,通过控制点,到结束点 CGPathAddQuadCurveToPoint(path, NULL, controlPoint.x, controlPoint.y, finalPoint.x, finalPoint.y); //CGPathRef,CGContextRef,CGColorRef //的基本类型都是CFtypeRef类型的 //而ARC不支持此类型的自动释放 //将cgpathref对象添加到自动释放池 CFAutorelease(path); //将路径返回 return path ; } @end
附件:
该程序的例子:
文件存到网盘了。百度网盘。