IOS 作业项目(2) 画图(保存,撤销,笔粗细设定功能)
先上效果图
一,项目建立
创建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) 画图(保存,撤销,笔粗细设定功能)的更多相关文章
- IOS 作业项目(4)步步完成 画图 程序(中续)
一,程序布局整理 前言://1,程序启动//2,程序流程框架//3,程序界面一致//4,程序界面功能, //这里只做页面的固定功能, //在首次创建界面时,我们会指定好固定事件触发前的固定方法 //至 ...
- IOS 作业项目(4)步步完成 画图 程序(剧终)
// // CHViewController.m // SuperDrawingSample // // Created by JaikenLI on 13-11-21. // Copyrig ...
- IOS 作业项目(4)步步完成 画图 程序(问题处理)终结
一,解决换色程序崩溃问题 程序崩溃是因为颜色的内存被释放,添加如下类的内容即可 @implementation TuyaPath - (id)init { self = [super init]; i ...
- IOS 作业项目(4)步步完成 画图 程序(中)
一,承接上文,继续本文 [UIButton buttonWithType:UIButtonTypeRoundedRect]; 如此声明的按钮才会有点击闪动的效果!如果直接frame方式声明就不会有. ...
- IOS 作业项目(4)步步完成 画图 程序(上)
先上流程图
- IOS 作业项目 TableView两个section中cell置顶功能实现
点击cell会置顶,其他的下移
- IOS 作业项目(3) 霓虹灯效果
先上效果图 #import "CHViewController.h"@interface CHViewController (){ int i; int j;}@pro ...
- IOS 作业项目(1) 关灯游戏 (百行代码搞定)
1,准备工作,既然要开关灯,就需要确定灯的灯的颜色状态 首先想到的是扩展UIColor
- iOS重构项目之路
iOS重构项目之路 1.整理目录 按照功能模块对整个工程的目录进行分类,比如 2.整理资源文件 删除多余的图片文件,资源文件 图片资源尽量添加到Assets.xcassets中 删除项目中未引用的图片 ...
随机推荐
- JavaScript中给对象添加函数的方式
1. function 类名(){ this.属性: } var 对象名=new 类名(): function 函数名(){ //执行代码 } 对象名.属性名=函数名: 对象名.属性名(): func ...
- file类之目录
可以解决的问题是: 有时需要列出目录下指定类型的文件,比如java,txt等扩展名的文件,可以使用File类的下述两个方法,列出指定类型的文件. /* file类实现两个 ...
- <spring:message> 标签
可以使用<spring:message>标签结合 ResourceBundleMessageSource 的功能,在网页上显示 messages.properties 中的文字讯息,例如在 ...
- Checked 和 UnChecked 异常 的使用场合
异常的概念 任何的异常都是Throwable类(为何不是接口??),并且在它之下包含两个子类Error / Exception,而Error仅在当在Java虚拟机中发生动态连接失败或其它的定位失败的 ...
- MATLAB实现矩阵分块相乘
要实现一下功能,这里$\bf{x}_i$为行向量 $${\bf{A}} = \left[ \begin{array}{l}{{\bf{x}}_1}\\{{\bf{x}}_2}\end{array} \ ...
- Spring学习(二)——Spring中的AOP的初步理解[转]
[前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring. ...
- eclipse-mysql-tomcat bug之旅
赶紧默念三遍google大法好... [连接数据库 servlet调用提示找不到可加载的driver,普通的.java文件没问题] 表示不服啊...明明可以连上啊...为什么多了几个中间界面就不好使了 ...
- C# 如何用计时器Timer控件实现停留几秒再做切换窗体的操作
C# Timer用法及实例详解 关于C# Timer类 在C#里关于定时器类就有3个 C# Timer使用的方法1.定义在System.Windows.Forms里 C# Timer使用的方法2.定 ...
- js继承实例
第一种方法:对象冒充(临时属性) 借用临时属性,指向超类,末了删除 function Person(name,gender){ this.name=name; this.gender=gender; ...
- [Js]JavaScript闭包和范围的快速测试
1. if (!("a" in window)) { var a = 1; } alert(a); [分析]代码含义:如果window不包含属性a,就声明一个变量a并赋值为1 ①J ...