zoukankan      html  css  js  c++  java
  • iOS:quartz2D绘图小项目(涂鸦画板)

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

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

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

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

    具体操作如下:

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

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

        

    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;
    }

    演示截图如下:

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

        

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

       

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

      

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

         

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

       

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

      

    绘制图片并保存到相册:

        

    查看保存的图片

     

    可以再双击隐藏工具栏:

  • 相关阅读:
    spring boot 若依系统整合Ueditor,部署时候上传图片错误解决
    JVM学习笔记之栈区
    据说这个是可以撸到2089年的idea2020.2
    小程序监听屏幕滑动事件
    小程序bindinput和bindblur赋值延迟问题解决
    小程序文件下载并保存文件名打开
    数据结构
    Spring JPA 自定义删改
    Spring JPA 查询创建
    Spring JPA 拓展
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/4875974.html
Copyright © 2011-2022 走看看