iOS:quartz2D绘图小项目(涂鸦画板)

摘要:
简介:在学习了石英2D的绘图知识后,我根据它的一些功能做了一个小项目:涂鸦绘图板。具体操作如下:1.创建上述类的屏幕截图:2.将用户定义的视图类DemiView与控制器的视图相关联:3.以下是每个类的代码:#import #import #definePHOTO在MyPath中。h_RECT//绘制照片本地宏定义@interfaceMyPath:NSObject@propertyCGMutablePathRefpath ;// Application中的变量路径@propertyUIColor*color//color@propertyNSIntegerlineWidth//线宽@propertyUIImage*image//image@end<2˃在m文件中:-Application:applicationdidFinishLaunchingWithOptions:launchOptions{//设置首选项NSUserDefaults*userDefaults=[NSUserDefaultssstandardUserDefaults];[userDefaultssetBool:YESForKey:@“isDefaultColor”];[userDefaultssetBool:YESForKey:@“isDefaulttLine”];[userDefaultssynchronize];returnYES;} 在DemoView类中,DemoView。h file#import @interfaceDemoView:UIView@propertyUIColor*颜色;//Color@propertyNSIntegerlineWidth//线宽@propertyNS可变数组*路径//变量数组,用于保存路径@propertyBOOLisUndo//标识符@propertyUIImage*图像//图像@propertyCGMaplePathRefpath//变量路径@endDemoView。m文件//延迟加载路径{if(!

介绍:学了quartz2D的绘图知识后,我根据它的一些功能制作了一个小项目:涂鸦画板。

功能:绘制各种图形,还可以选取相册上的照片做涂鸦,然后保存到相册中。其中,还包括功能有:颜色的选取、线宽的选取、橡皮擦除、撤销上一次绘制痕迹、清除所有痕迹。

用到的自定义控件:工具栏控件(UIToolBar)、工具栏上的按钮控件(UIBarButtonItem)、警告框控件(UIAlertView、UIActionSheet)、图像选择器控制器控件(UIImagePickerController)等。

需要的类:除了应用程序代理类AppDelegate和控制器类ViewController外,还需要一个自定义的视图类DemoView和一个自定义的绘制路径类MyPath。MyPath类是用来封装绘制路径的,因为路径是结构体,所以不能直接动作对象使用,封装后可以将路径保存数组中,用来连续绘图。

具体操作如下:

1、创建如上介绍的类的截图为:

iOS:quartz2D绘图小项目(涂鸦画板)第1张

2、将自定义的视图类DemiView与控制器的视图关联起来:

iOS:quartz2D绘图小项目(涂鸦画板)第2张   iOS:quartz2D绘图小项目(涂鸦画板)第3张 

3、下面就是具体针对每一个类的代码了:

<1>在MyPath.h文件中

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#define PHOTO_RECT (CGRectMake(0,0,375,667))//绘制照片局域宏定义
@interface MyPath : NSObject
@property (assign,nonatomic)CGMutablePathRef path;   //可变的路径
@property (strong,nonatomic)UIColor *color;  //颜色
@property (assign,nonatomic)NSInteger lineWidth; //线宽
@property (strong,nonatomic)UIImage *image;//图像
@end

<2>在Application.m文件中:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    //设置偏好
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setBool:YES forKey:@"isDefualtColor"];
    [userDefaults setBool:YES forKey:@"isDefualtLine"];
    [userDefaults synchronize];
    
    return YES;
}

<3>在DemoView类中

DemoView.h文件

#import <UIKit/UIKit.h>
@interface DemoView : UIView
@property (strong,nonatomic)UIColor *color;        //颜色
@property (assign,nonatomic)NSInteger lineWidth;   //线宽
@property (strong,nonatomic)NSMutableArray *paths; //可变数组,用来保存路径
@property(assign,nonatomic)BOOL isUndo;  //标示符
@property (strong,nonatomic)UIImage *image; //图像
@property (assign,nonatomic)CGMutablePathRef path; //可变的路径
@end

DemoView.m文件

//懒加载

-(NSMutableArray*)paths
{
    if (!_paths)
    {
        _paths = [NSMutableArray array];
    }
    return _paths;
}

 //画图

- (void)drawRect:(CGRect)rect
{    
    //1.获取绘制图上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    //4.添加保存的路径到上下文
    for (MyPath *myPath in self.paths)
    {
        CGContextAddPath(context, myPath.path);
        
        if(myPath.image)
        {
            [myPath.image drawInRect:PHOTO_RECT];
        }
        
        //设置绘图属性
        [myPath.color set];
        CGContextSetLineWidth(context, myPath.lineWidth);
        
        //绘制路径
        CGContextDrawPath(context, kCGPathStroke);
    }
    
    
    //如果是清除或撤销,就不执行当前绘图
    if (!self.isUndo)
    {
        if(self.image)
        {
            [self.image drawInRect:PHOTO_RECT];
        }
        
        //添加当前路径
        CGContextAddPath(context, _path);
        
        //5.设置当前绘图属性
        [self.color set];
        CGContextSetLineWidth(context, self.lineWidth);
        
        //6.绘制路径
        CGContextDrawPath(context, kCGPathStroke);
    }
}

//开始触摸事件(设置绘制属性)

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.isUndo = NO;
    
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];    
    if ([userDefaults boolForKey:@"isDefualtColor"])
    {
        //设置默认颜色
        self.color = [UIColor blackColor];
    }
    if ([userDefaults boolForKey:@"isDefualtLine"])
    {
        //设置默认线宽
        self.lineWidth = 1.0;
    }
    
    //接收颜色通知
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(seclectColor:) name:@"ColorNitification" object:nil];
    
    //接收线宽通知
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(selectedWidth:) name:@"WidthNitification"  object:nil];
    
    
    //创建路径
    _path = CGPathCreateMutable();
    
    //创建起始点
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];
    CGPathMoveToPoint(_path, nil, location.x, location.y);
}

//获取通知中的颜色和线宽数据

//从通知中获取颜色
-(void)seclectColor:(NSNotification*)notification
{
    self.color = notification.object;
    
    if (self.color == NULL)
    {
        self.color = [UIColor blackColor];
    }
}

//从通知中获取线宽
-(void)selectedWidth:(NSNotification*) notification
{
    NSNumber *number = notification.object;
    self.lineWidth = [number integerValue];
    if (self.lineWidth == 0)
    {
        self.lineWidth = 1.0;
    }
}

//触摸移动(添加新路径,刷新视图)

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (_path)
    {
        //向路径添加新的直线
        UITouch *touch = [touches anyObject];
        CGPoint location = [touch locationInView:self];
        CGPathAddLineToPoint(_path, nil, location.x, location.y);
        
        //让视图刷新
        [self setNeedsDisplay];
    }
}

//触摸结束(封装路径并保存到数组中)

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (_path)
    {
        //保存路径
        MyPath *myPath = [[MyPath alloc]init];
        myPath.path = self.path;
        myPath.color = self.color;
        myPath.lineWidth = self.lineWidth;
        
        if(self.image)
        {
            myPath.image = self.image;
            self.image = nil;
        }
        
//保存路径 [self.paths addObject:myPath]; } }

//清理路径

-(void)dealloc
{
    //清理保存的路径
    for (MyPath *myPath in self.paths)
    {
        CGPathRelease(myPath.path);
    }
}

<4>在ViewController.m文件中

//设置属性

@interface ViewController ()<UIAlertViewDelegate,UIActionSheetDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate>
@property (strong,nonatomic)UIToolbar *toolBar;
@property (strong,nonatomic)NSMutableDictionary *DicM;

@end

//初始化和创建控件

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //初始化
    self.DicM = [NSMutableDictionary dictionary];
    ((DemoView *)self.view).isUndo = NO;
    
    //创建工具栏对象
    self.toolBar = [[UIToolbar alloc]init];
    self.toolBar.barTintColor = [UIColor brownColor];
    self.toolBar.frame = CGRectMake(0, 0, 375, 40);
    
    
    
    //创建工具栏项目
    UIBarButtonItem *colorItem = [[UIBarButtonItem alloc]initWithTitle:@"颜色" style:UIBarButtonItemStylePlain target:self action:@selector(SelectColor:)];
    
    UIBarButtonItem *lineWidthItem = [[UIBarButtonItem alloc]initWithTitle:@"线宽" style:UIBarButtonItemStylePlain target:self action:@selector(SelectWidth:)];
    
    UIBarButtonItem *clearpartItem = [[UIBarButtonItem alloc]initWithTitle:@"橡皮" style:UIBarButtonItemStylePlain target:self action:@selector(ClearPart:)];
    
    UIBarButtonItem *backdoneItem = [[UIBarButtonItem alloc]initWithTitle:@"撤销" style:UIBarButtonItemStylePlain target:self action:@selector(BackDone:)];
    
    UIBarButtonItem *clearallItem = [[UIBarButtonItem alloc]initWithTitle:@"清空" style:UIBarButtonItemStylePlain target:self action:@selector(ClearAll:)];
    
    UIBarButtonItem *photoItem = [[UIBarButtonItem alloc]initWithTitle:@"照片" style:UIBarButtonItemStylePlain target:self action:@selector(selectPhoto:)];
    
    UIBarButtonItem *saveItem = [[UIBarButtonItem alloc]initWithTitle:@"保存" style:UIBarButtonItemStylePlain target:self action:@selector(Save:)];
    
    UIBarButtonItem *flexibleItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
    
    [self.toolBar setItems:@[colorItem,flexibleItem,lineWidthItem,flexibleItem,clearpartItem,flexibleItem,backdoneItem,flexibleItem,clearallItem,flexibleItem,photoItem,flexibleItem,saveItem]];
    
    [self.view addSubview:self.toolBar];
    
//开始时隐藏工具栏 self.toolBar.hidden
= YES; //创建点击手势(双击时显示和隐藏工具栏) UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(showToolBar:)]; //设置点击次数 tap.numberOfTapsRequired = 2; //添加手势 [self.view addGestureRecognizer:tap]; }

//设置颜色选项

//选择颜色
-(void)SelectColor:(UIBarButtonItem *)sender
{
    UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:nil message:@"可选颜色" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"红色",@"绿色",@"紫色",@"黄色",@"黑色",@"白色",@"蓝色",@"灰色",@"棕色",nil];
    
    
    [self.DicM setObject:[UIColor redColor]   forKey:@"红色"];
    [self.DicM setObject:[UIColor greenColor] forKey:@"绿色"];
    [self.DicM setObject:[UIColor purpleColor]forKey:@"紫色"];
    [self.DicM setObject:[UIColor yellowColor]forKey:@"黄色"];
    [self.DicM setObject:[UIColor blackColor] forKey:@"黑色"];
    [self.DicM setObject:[UIColor whiteColor] forKey:@"白色"];
    [self.DicM setObject:[UIColor blueColor]  forKey:@"蓝色"];
    [self.DicM setObject:[UIColor grayColor]  forKey:@"灰色"];
    [self.DicM setObject:[UIColor brownColor] forKey:@"棕色"];
    
    [alertView show];
}

//设置线宽选项

//选择线宽
-(void)SelectWidth:(UIBarButtonItem *)sender
{
    UIActionSheet *actionSheet = [[UIActionSheet alloc]initWithTitle:@"可选线宽" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"1号",@"2号",@"3号",@"4号",@"5号",@"6号",@"7号",@"8号",@"9号",@"10号",nil];
    
    [self.DicM setObject:[NSNumber numberWithInteger:1]  forKey:@"1号"];
    [self.DicM setObject:[NSNumber numberWithInteger:2]  forKey:@"2号"];
    [self.DicM setObject:[NSNumber numberWithInteger:3]  forKey:@"3号"];
    [self.DicM setObject:[NSNumber numberWithInteger:4]  forKey:@"4号"];
    [self.DicM setObject:[NSNumber numberWithInteger:5]  forKey:@"5号"];
    [self.DicM setObject:[NSNumber numberWithInteger:6]  forKey:@"6号"];
    [self.DicM setObject:[NSNumber numberWithInteger:7]  forKey:@"7号"];
    [self.DicM setObject:[NSNumber numberWithInteger:8]  forKey:@"8号"];
    [self.DicM setObject:[NSNumber numberWithInteger:9]  forKey:@"9号"];
    [self.DicM setObject:[NSNumber numberWithInteger:10] forKey:@"10号"];
    
    [actionSheet showInView:self.view];
}

//实现UIAlertView警告框协议

#pragma mark -<UIAlertViewDelegate>
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    NSString *key = [alertView buttonTitleAtIndex:buttonIndex];
    
    UIColor *selectedcolor = [self.DicM objectForKey:key];

    //发送通知附带颜色数据
    [[NSNotificationCenter defaultCenter]postNotificationName:@"ColorNitification" object:selectedcolor];
    
    //重设偏好
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isDefualtColor"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

//实现UIActionSheet警告框协议

#pragma mark -<UIActionSheetDelegate>
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    NSString *key = [actionSheet buttonTitleAtIndex:buttonIndex];
    
    NSNumber *number = [self.DicM objectForKey:key];
    
    
    //发送通知附带线宽数据
    [[NSNotificationCenter defaultCenter]postNotificationName:@"WidthNitification" object:number];
    
    //重设偏好
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isDefualtLine"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

//擦除功能

//橡皮擦除(其实就是用白色重绘)
-(void)ClearPart:(UIBarButtonItem *)sender
{
    UIColor *selectedcolor = [UIColor whiteColor];
    [[NSNotificationCenter defaultCenter]postNotificationName:@"ColorNitification" object:selectedcolor];
    
    NSNumber *number = [NSNumber numberWithInteger:10];
    [[NSNotificationCenter defaultCenter]postNotificationName:@"WidthNitification" object:number];
    
    //重设偏好
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isDefualtColor"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isDefualtLine"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

//撤销功能

//撤销
-(void)BackDone:(UIBarButtonItem *)sender
{
    //先做清理工作
    MyPath *path = [((DemoView *)self.view).paths lastObject];
    CGPathRelease(path.path);
    
    //删除最后一个路径
    [((DemoView *)self.view).paths removeLastObject];
    ((DemoView *)self.view).image = nil;
    
    ((DemoView *)self.view).isUndo = YES;
    
    //让视图重绘
    [self.view setNeedsDisplay];
}

//清空功能

//清空绘图
-(void)ClearAll:(UIBarButtonItem *)sender
{
    //先做清理工作
    for(MyPath *path in ((DemoView *)self.view).paths)
    {
        CGPathRelease(path.path);
    }
    //删除所有
    [((DemoView *)self.view).paths removeAllObjects];
    ((DemoView *)self.view).image = nil;
    
    ((DemoView *)self.view).isUndo = YES;
    
    //让视图重绘
    [self.view setNeedsDisplay];
}

//保存绘图功能

//保存绘图
-(void)Save:(UIBarButtonItem *)sender
{
    [self didSelectedSave];
}
-(void)didSelectedSave
{
    //开始图像绘制上下文
    UIGraphicsBeginImageContext(self.view.bounds.size);
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 先画保存的path
    for(MyPath *myPath in ((DemoView *)self.view).paths)
    {
        if(myPath.image)
        {
            [myPath.image drawInRect: PHOTO_RECT ];
        }
        
        CGContextAddPath(context, myPath.path);
        [myPath.color set];
        CGContextSetLineWidth(context, myPath.lineWidth);
        CGContextStrokePath(context);
    }
    
    //获取绘制的图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
    //结束图像绘制上下文
    UIGraphicsEndImageContext();
    
    //保存图片
    UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
- (void)image: (UIImage *) image
    didFinishSavingWithError: (NSError *) error
                 contextInfo: (void *) contextInfo
{
    NSString *msg = nil;
    if(error)
    {
        msg = @"图片保存失败";
    }
    else
    {
        msg = @"图片保存成功";
    }
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"保存图片" message:msg delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];
}

//选取照片功能

//选取照片
-(void)selectPhoto:(UIBarButtonItem*)sender
{
    [self didSelectedPhoto];
}

-(void)didSelectedPhoto
{
    //显示照片选择窗口
    UIImagePickerController *picker = [[UIImagePickerController alloc]init];
    
    //图片来源是相册
    picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    
    
    picker.delegate = self;
    
    //以模态窗口的形式显示图片
    [self presentViewController:picker animated:YES completion:nil];
}

//图像选择器控制器协议方法

#pragma mark - imagePikerController 代理方法
//选取图片
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    //取出图片
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
    
    ((DemoView *)self.view).image = image;
    
    ((DemoView *)self.view).isUndo = NO;
    
    //创建路径
    ((DemoView *)self.view).path = CGPathCreateMutable();
    
    
    //关闭模态窗口
    [picker dismissViewControllerAnimated:YES completion:nil];
    
    //刷新视图
    [self.view setNeedsDisplay];
}

//手势事件,是否显示工具栏

//按钮事件是否显示工具栏
-(void)showToolBar:(UIButton *)sender
{
    self.toolBar.hidden = !self.toolBar.hidden;
}

演示截图如下:

开始时:                                             双击显示工具栏:

iOS:quartz2D绘图小项目(涂鸦画板)第4张    iOS:quartz2D绘图小项目(涂鸦画板)第5张

(使用默认颜色和线宽)绘制直线                                            选颜色绘制直线 ,选红色 

iOS:quartz2D绘图小项目(涂鸦画板)第6张   iOS:quartz2D绘图小项目(涂鸦画板)第7张

iOS:quartz2D绘图小项目(涂鸦画板)第8张

接着选择线宽绘制直线:选10号

iOS:quartz2D绘图小项目(涂鸦画板)第9张  iOS:quartz2D绘图小项目(涂鸦画板)第10张

点击橡皮擦除:                         点击撤销,被擦除部分还原

iOS:quartz2D绘图小项目(涂鸦画板)第11张     iOS:quartz2D绘图小项目(涂鸦画板)第12张

点击清空,什么都没有了:                                                 点击照片,打开相册   

iOS:quartz2D绘图小项目(涂鸦画板)第13张   iOS:quartz2D绘图小项目(涂鸦画板)第14张

任意选取一张照片,选取X

iOS:quartz2D绘图小项目(涂鸦画板)第15张  iOS:quartz2D绘图小项目(涂鸦画板)第16张

绘制图片并保存到相册:

iOS:quartz2D绘图小项目(涂鸦画板)第17张    iOS:quartz2D绘图小项目(涂鸦画板)第18张

查看保存的图片

iOS:quartz2D绘图小项目(涂鸦画板)第19张 iOS:quartz2D绘图小项目(涂鸦画板)第20张

可以再双击隐藏工具栏:

iOS:quartz2D绘图小项目(涂鸦画板)第21张

免责声明:文章转载自《iOS:quartz2D绘图小项目(涂鸦画板)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇TOMCAT 启动报错 INVALID CHARACTER FOUND IN METHOD NAME. HTTP METHOD NAMES MUST BE TOKENSRT-Thread OS的启动流程下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ios用户登录记住密码

登录 记录已登录用户步骤,存入偏好设置中存储放入一个数组。 具体存储 1:存储用户到偏好设置中,其中用户是一个数组 向服务器响应客户端后的一些操作 (如果响应数据成功)其中用户和密码是一一对应的 1.1先从沙盒中偏好设置中读取对应的用户集合 读取用户名: NSMutableArray *AccArys =[NSMutab...

iOS 本地存储四种方法

在iOS开发过程中,不管是做什么应用,都会碰到数据保存的问题。将数据保存到本地,能够让程序的运行更加流畅,不会出现让人厌恶的菊花形状,使得用户体验更好。下面介绍⼀一下数据保存的方式: 1.NSKeyedArchiver:采用归档的形式来保存数据,该数据对象需要遵守NSCoding协议,并且该对象对应的类必须提 供encodeWithCoder:和init...

iOS开发之沙盒机制

iOS应用储存分以下几种: 一、沙盒基本机制 二、plist储存 三、偏好设置 四、NSKeydeArchiver归档 一、沙盒基本机制(sandbox) iOS系统相对于Android系统,或者相对于Windows系统来说比较安全的原因很多,其中有一点就是苹果推出的沙盒机制,每个应用都有自己对应的沙盒,每个应用程序之间不能相互访问非本程序的沙盒,所以,...

iOS 数据持久化 NSUserDefault

每一个应用都有一个 NSUserDefaults 实例,向 NSUserDefaults 类发送 standardUserDefaults 消息可以得到该实例。 NSUserDefaults 实例类似与 NSMutableDictionary,可以通过键存取或删除该对象。 当应用第一次使用 NSUserDefaults 实例时,NSUserDefaults...

豆瓣客户端(二)获取用户信息和搜索用户

之前写了豆瓣客户端(一)获取授权码和访问令牌后,就开始学习iOS7 TextKit方面的内容了,在前两天看Text Kit 看得无聊以后,又再回来写自己一直都很感兴趣的豆瓣客户端。途中遇到了各种各样的问题,先来小小吐槽一下:豆瓣的开发文档真是坑爹极了,基本上没有步骤可言,有时候就是一句带过,来个只能意会不能言传,难怪那么少人做豆瓣客户端,可能这个客户端赚不...

ios 保存本地数据的方法

1。 NSString *path = [[NSBundle mainBundle] pathForResource:@"文件名" ofType:@"plist"]; // 文件数据类型是array NSArray *array=[NSArray arrayWithContentsOfFile:path]; //文件数据类型是*dictionary NSD...