先上效果图

一,项目建立

创建Single View Application项目,为项目添加类CustomPath  CustomManager 都继承自NSObject,CustomView继承自UIView

1,CustomPath.h中内容:

@interface CustomPath : NSObject
//设置路径,路径颜色,路径宽度
@property(nonatomic,assign)CGMutablePathRef linePath;
@property (nonatomic,assign)CGFloat lineWidth;
@property (nonatomic,assign)CGColorRef lineColor;
@end
这个类主要记录线条数据,.m文件不用写内容

2,CustomManager是单例类,主要控制CustomPath属性等,在整个项目中数据共享,这里涉及到了单例,在.h文件中内容如下:

//单例前缀一般都为:signleton default instance shared
@interface CustomManager : NSObject
//单例方法
+(CustomManager *)defaultManager;
//存储路径的数组
@property (nonatomic,strong)NSMutableArray *pathList;
@end

在.m文件中,内容如下:

@implementation CustomManager
+(CustomManager *)defaultManager
{
    @synchronized(self)
    {
        static CustomManager*s_CustomManager=nil;//静态对象,当再次实例化的时候,这句代码不起作用,这点和c语言静态数据类型一样.
        if (s_CustomManager==nil) {//如果为nil,则是第一次初始化,执行下面的创建对象语句,如果不是nil则返回,这样就保证了单例一直是一个对象
            s_CustomManager=[CustomManager new];
        }
        return s_CustomManager;
    }
}
-(id)init    //单例初始化的时候对其内部数据进行初始化
{
    if(self=[super init])
    {
        self.pathList=[NSMutableArray new];
    }
    return self;
}
@end
3,CustomView文件控制画图操作

.h文件内容如下:

@interface CustomView : UIView
@property (nonatomic,retain)UIColor *lineColor;
@property (nonatomic,assign)NSInteger lineWidth;
//创建中间变量图片,用来存储每次的视图的截图,画图效率统一,没有程序运行的变化//缺点需要添加新技术,通过视图获取图片
@property (nonatomic,strong) UIImage *tempImage;
@property (nonatomic,assign)CGMutablePathRef totalPath;
-(UIImage *)getImageFromCurrentContext;

.m文件内容如下:

@implementation CustomView
{
    //添加似有的成员变量,启动和结束的点
    CGPoint startPoint;
    CGPoint controlPoint;
    CGPoint endPoint;   
    //声明路径私有成员变量,解决计算效率
    CGMutablePathRef tempPath;
    //每次触摸完成后的路径
    CGMutablePathRef touchPath;
}
@synthesize  lineColor;
@synthesize lineWidth;
@synthesize tempImage;
@synthesize totalPath;//声明全部路径变量,用来存储所有的中间变量   
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        startPoint=CGPointZero;
        controlPoint=CGPointZero;
        endPoint=CGPointZero;
        totalPath=CGPathCreateMutable();//创建全部路径对象存储空间
    }
    return self;
}

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];
    if (CGPointEqualToPoint(startPoint, CGPointZero)&&CGPointEqualToPoint(endPoint, CGPointZero)) {
        return;
    }
    //获取当前画布
    CGContextRef context=UIGraphicsGetCurrentContext();
    for (CustomPath *itempath in [CustomManager defaultManager].pathList) {
        CGContextSetLineCap(context, kCGLineCapRound);
        CGContextSetLineWidth(context, itempath.lineWidth);
        CGContextSetStrokeColorWithColor(context, itempath.lineColor);
        CGContextAddPath(context, itempath.linePath);
        CGContextStrokePath(context);
    }
}

#pragma mark color
-(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];
    controlPoint=[touch previousLocationInView:self];
    endPoint=[touch locationInView:self];
    //调用方法
    //[self touchesMoved:touches withEvent:event];
}
//每当触摸的时候先获取触摸对象,下面添加两个触摸方法
//当手指触摸时,实现的方法
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch=[touches anyObject];
    startPoint=controlPoint;//设置起点
    controlPoint=[touch previousLocationInView:self];//设置控制点为前一个触摸点
    endPoint=[touch locationInView:self];//设置中点为当前触摸点
    //生成截图图片对象
    tempImage=[self getImageFromCurrentContext];
    //通知本视图,开始执行drawRect方法
    tempPath=[self pathFromPoint:midPoint(startPoint, controlPoint) toPoint:midPoint(controlPoint, endPoint)];
    //获取最小的能容纳路径的矩形体积
    CGRect rect=CGPathGetBoundingBox(tempPath);
    rect.origin.x-=15.f;
    rect.origin.y-=15.f;
    rect.size.height+=30.f;
    rect.size.width+=30.f;
    //将中间变量tempPath添加到全部路径变量totalPath内
    CGPathAddPath(totalPath, NULL, tempPath);
    //将中间变量tempPath添加到每一次的触摸路径touchPaht内
    CGPathAddPath(touchPath, NULL, tempPath);
    //修改最后的自定义path对象
    CustomPath *itemPath=[[CustomManager defaultManager].pathList lastObject];
    itemPath.linePath=touchPath;
    //设置当前视图需要重绘的矩形区域
    [self setNeedsDisplayInRect:rect];
   //' [self setNeedsDisplay];

}

//当手指结束,实现的方法
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    CustomPath *itemPath=[[CustomManager defaultManager].pathList lastObject];
    itemPath.linePath=touchPath;
}
-(UIImage *)getImageFromCurrentContext
{
    //1开始创建图片画布
    UIGraphicsBeginImageContext(self.bounds.size);
    //2将视图的内容渲染到图片画布上
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];//当前画布不是视图画布
    //3,通过图片画布获取图片
    UIImage *result=UIGraphicsGetImageFromCurrentImageContext();
    //4,结束图片画布
    UIGraphicsEndImageContext();
    return  result;
}
static inline CGPoint midPoint(CGPoint point1,CGPoint point2)
{
    CGFloat midx=(point1.x+point2.x)/2.0f;
    CGFloat midy=(point2.y+point1.y)/2.0f;
    return  CGPointMake(midx, midy);
}

//获取坐标内的路径
-(CGMutablePathRef)pathFromPoint:(CGPoint)originPoint toPoint:(CGPoint)finalPoint
{
    CGMutablePathRef path=CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, originPoint.x, originPoint.y);//  移动到出发点
     //添加曲线,通过控制点到结束点
    CGPathAddQuadCurveToPoint(path, NULL, controlPoint.x, controlPoint.y, finalPoint.x, finalPoint.y);
   
    CFAutorelease(path);
    return path;
}

@end
以上CustomView.m中的内容是重点,画图原理都在这个文件里.

4,最后在ViewController文件里调用以上内容

#import "CHViewController.h"
#import "CustomView.h"
#import "CustomPath.h"
#import "CustomManager.h"

@implementation CHViewController
{
    NSInteger imgCount;
}
CustomView *cView;
UIImageView *v1,*v2,*v3,*v11,*v22,*v33;//六个视图声明变量
- (void)viewDidLoad
{
    //初始状态图片个数为0
    imgCount=0;
    
    [super viewDidLoad];
    //创建黑色容器视图,大小和根视图大小相同,位置以根视图坐标原点为起点
    UIView *containerView=[[UIView alloc]initWithFrame:self.view.bounds];
    containerView.backgroundColor=[UIColor orangeColor];
    [self.view addSubview:containerView];
    //标题view
    UIView *titleView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 20)];
    titleView.backgroundColor=[UIColor blackColor];
    [titleView setAlpha:0.5];
    [containerView addSubview:titleView];

cView=[CustomView new];
    cView.frame=CGRectMake(10, 220, 300, 250);
    cView.backgroundColor=[UIColor whiteColor];
    cView.lineColor=[UIColor greenColor];
     [containerView addSubview:cView];
    //slider View and cancelButton saveButton
    UISlider *slider=[[UISlider alloc]initWithFrame:CGRectMake(60, 20, 200, 40)];
    slider.minimumValue=4;
    slider.maximumValue=15;
   [slider addTarget:self action:@selector(sliderMove:) forControlEvents:UIControlEventValueChanged];
       [containerView addSubview:slider];
    UIButton *cancelButton=[[UIButton alloc]initWithFrame:CGRectMake(0, 20, 60, 40)];
    [cancelButton setTitle:@"撤销" forState:UIControlStateNormal];
    [cancelButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [cancelButton addTarget:self action:@selector(cancelButtonOnClick:) forControlEvents:UIControlEventTouchDown];
    [containerView addSubview:cancelButton];
 
    UIButton *saveButton=[[UIButton alloc]initWithFrame:CGRectMake(260, 20, 60, 40)];
    [saveButton setTitle:@"保存" forState:UIControlStateNormal];
    [saveButton addTarget:self action:@selector(saveButtonOnClick:) forControlEvents:UIControlEventTouchDown];
    [saveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [containerView addSubview:saveButton];
    ///////绘图区
    
    //图片区,六个UIImageView视图的显示属性设置
    v1=[self imageView:CGRectMake(10, 70, 70, 70)];
    v2=[self imageView:CGRectMake(115, 70, 70, 70)];
    v3=[self imageView:CGRectMake(220, 70, 70, 70)];
    v11=[self imageView:CGRectMake(10, 145, 70, 70)];
    v22=[self imageView:CGRectMake(115, 145, 70, 70)];
    v33=[self imageView:CGRectMake(220, 145, 70, 70)];
    [containerView addSubview:v1];
    [containerView addSubview:v2];
    [containerView addSubview:v3];
    [containerView addSubview:v11];
    [containerView addSubview:v22];
    [containerView addSubview:v33];
}
//六个UIImageView用于显示点击保存后的图片快照
-(UIImageView *)imageView:(CGRect)rect
{
    UIImageView *v=[[UIImageView alloc]initWithFrame:rect];
    v.backgroundColor=[UIColor whiteColor] ;
    return v;
}
-(void)cancelButtonOnClick:(UIButton *)button
{
    [[CustomManager defaultManager].pathList removeLastObject];
    [cView setNeedsDisplay];
}

-(void)saveButtonOnClick:(UIButton *)button
{
    imgCount++;
    
    
   UIImage *image= [cView getImageFromCurrentContext];
    
    
     UIImageWriteToSavedPhotosAlbum(image, Nil, Nil, Nil);
    if (imgCount>6) {
        imgCount=1;
    }
    switch (imgCount) {
        case 1:
            v1.image=image;
            break;
        case 2:
            v2.image=image;
            break;

case 3:
            v3.image=image;
            break;

case 4:
            v11.image=image;
            break;

case 5:
            v22.image=image;
            break;

case 6:
            v33.image=image;
            break;
                  
    }
}
//slider moved to change containerView's property
-(void)sliderMove:(UISlider*) slider
{
    cView.lineWidth=slider.value;
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

IOS 作业项目(2) 画图(保存,撤销,笔粗细设定功能)的更多相关文章

  1. IOS 作业项目(4)步步完成 画图 程序(中续)

    一,程序布局整理 前言://1,程序启动//2,程序流程框架//3,程序界面一致//4,程序界面功能, //这里只做页面的固定功能, //在首次创建界面时,我们会指定好固定事件触发前的固定方法 //至 ...

  2. IOS 作业项目(4)步步完成 画图 程序(剧终)

    // //  CHViewController.m //  SuperDrawingSample // //  Created by JaikenLI on 13-11-21. //  Copyrig ...

  3. IOS 作业项目(4)步步完成 画图 程序(问题处理)终结

    一,解决换色程序崩溃问题 程序崩溃是因为颜色的内存被释放,添加如下类的内容即可 @implementation TuyaPath - (id)init { self = [super init]; i ...

  4. IOS 作业项目(4)步步完成 画图 程序(中)

    一,承接上文,继续本文  [UIButton buttonWithType:UIButtonTypeRoundedRect]; 如此声明的按钮才会有点击闪动的效果!如果直接frame方式声明就不会有. ...

  5. IOS 作业项目(4)步步完成 画图 程序(上)

    先上流程图

  6. IOS 作业项目 TableView两个section中cell置顶功能实现

    点击cell会置顶,其他的下移

  7. IOS 作业项目(3) 霓虹灯效果

    先上效果图 #import "CHViewController.h"@interface CHViewController (){    int i;    int j;}@pro ...

  8. IOS 作业项目(1) 关灯游戏 (百行代码搞定)

    1,准备工作,既然要开关灯,就需要确定灯的灯的颜色状态 首先想到的是扩展UIColor

  9. iOS重构项目之路

    iOS重构项目之路 1.整理目录 按照功能模块对整个工程的目录进行分类,比如 2.整理资源文件 删除多余的图片文件,资源文件 图片资源尽量添加到Assets.xcassets中 删除项目中未引用的图片 ...

随机推荐

  1. sleep函数

    Linux下: #include <unistd.h> sleep(1); // 睡眠1秒 usleep(1); // 睡眠1微妙

  2. MYSQL的三种注释

    #CREATE SCHEMA `paw-jj` DEFAULT CHARACTER SET utf8 ; -- select * from vrv_paw_terminalinfo /*  selec ...

  3. sqlserver 修改替换text,ntext类型字段的两种方案

    方案一 用Update和Replace --替换语句(因为varchar(max)最大值是8000,所以大于8000的部分会被截掉) UPDATE dbo.SNS_UserBlog SET [Desc ...

  4. 前端面试题之nina分享

    HTML相关 1.<!DOCTYPE>标签的定义与用法. <!DOCTYPE>的定义: <!DOCTYPE>声明位于文档中的最前面的位置,处于<html> ...

  5. Spring学习(二)——Spring中的AOP的初步理解[转]

      [前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring. ...

  6. Linux下配置用msmtp和mutt发邮件

    Linux下可以直接用mail命令发送邮件,但是发件人是user@servername,如果机器没有外网的dns,其他人就无法回复.此时,有一个可以使用网络免费邮箱服务的邮件发送程序就比较重要了.ms ...

  7. PMP项目管理笔记 项目定义

    项目的定义 项目是为创造独特的产品,服务或成果而进行临时性的工作. 项目是组织的经营需要与战略目标服务的. PMBOK 指南描述的项目管理知识,从本质上讲,是用来管理中等或以上规模,跨部门,跨专业的目 ...

  8. 二分图 最大权匹配 km算法

    这个算法的本质还是不断的找增广路: KM算法的正确性基于以下定理:若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最 ...

  9. 在Excel中引用其他宏

    在excel的使用过程中,会用到一些自定义函数,可以使用宏轻松的实现这些功能,问题是必须使用“启用宏的excel”,这样用户每次打开时都要启用宏. 现用以按背景色计划为例,解决以上问题: 1.新建一个 ...

  10. set常见操作:

    (1)sadd 向一个集合中添加一个元素.例如:sadd set1 Hello (2)smembers 查看集合中的所有元素.例如:smembers set1 (3)srem 删除集合中一个指定的元素 ...