iOS开发之画图板(贝塞尔曲线)

  贝塞尔曲线,听着挺牛气一词,不过下面我们在做画图板的时候就用到贝塞尔绘直线,没用到绘制曲线的功能。如果会点PS的小伙伴会对贝塞尔曲线有更直观的理解。这篇博文的重点不在于如何用使用贝塞尔曲线,而是利用贝塞尔划线的功能来封装一个画图板。

  画图板的截图如下,上面的白板就是我们的画图板,是自己封装好的一个UIView,下面会详细的介绍如何封装这个画图板,下面的控件用来控制我们画图板的属性以及Undo,Redo和保存功能。点击保存时会把绘制的图片保存到手机的相册中。下面是具体的实现方案。

  一.封装画图板

    其实上面的白板就是一继承于UiView的一个子类,我们可以在这个子类中添加我们画图板相应的属性和方法,然后实例化成对象添加到ViewController中,当然为了省事添加白板的时候是通过storyboard来完成的,读者也可以自己实例化然后手动的添加到相应的ViewController中。

    1.封装白板的第一步是新建一个UIView的子类MyView,然后添加相应的属性和方法。MyView.h中的代码如下,代码具体意思请参照注释

 1 #import <UIKit/UIKit.h>
 2
 3 @interface MyView : UIView
 4 //用来设置线条的颜色
 5 @property (nonatomic, strong) UIColor *color;
 6 //用来设置线条的宽度
 7 @property (nonatomic, assign) CGFloat lineWidth;
 8 //用来记录已有线条
 9 @property (nonatomic, strong) NSMutableArray *allLine;
10
11 //初始化相关参数
12 -(void)initMyView;
13 //unDo操作
14 -(void)backImage;
15 //reDo操作
16 -(void)forwardImage;
17
18 @end

    2、上面的代码是对外的接口,有些属性我们是写在MyView.m的延展中以实现私有的目的,MyView延展部分如下:

1 @interface MyView()
2 //声明贝塞尔曲线
3 @property(nonatomic, strong) UIBezierPath *bezier;
4 //存储Undo出来的线条
5 @property(nonatomic, strong) NSMutableArray *cancleArray;
6 @end

    3.下面的代码就是实现部分的代码了,会根据不同功能给出相应的说明

      (1).初始化我们的白板,给线条指定默认颜色和宽度并且给相应的变量分配内存空间,初始化代码如下:

1 //进行一些初始化工作
2 -(void)initMyView
3 {
4     self.color = [UIColor redColor];
5     self.lineWidth = 1;
6     self.allLine = [NSMutableArray arrayWithCapacity:50];
7     self.cancleArray = [NSMutableArray arrayWithCapacity:50];
8 }

  

      (2)Undo功能的封装,相当于两个栈,把显示的线条出栈,进入为不显示的线条栈中,每执行一次此操作显示线条栈中的元素会少一条而不显示线条栈中会多一条,大致就这个意思吧,代码如下:

 1 //UnDo操作
 2 -(void)backImage
 3 {
 4     if (self.allLine.count > 0)
 5     {
 6         int index = self.allLine.count - 1;
 7
 8         [self.cancleArray addObject:self.allLine[index]];
 9
10         [self.allLine removeObjectAtIndex:index];
11
12         [self setNeedsDisplay
13          ];
14     }
15 }

    

      (3)Redo操作和Undo操作相反,从未显示栈中取出元素放入显示的栈中,代码中的栈我们是用数组来表示的,代码如下:

//ReDo操作
-(void)forwardImage
{
    if (self.cancleArray.count > 0)
    {
        int index = self.cancleArray.count - 1;

        [self.allLine addObject:self.cancleArray[index]];

        [self.cancleArray removeObjectAtIndex:index];

        [self setNeedsDisplay];
    }
}

      (4)、当开始触摸时我们新建一个BezierPath,把触摸起点设置成BezierPath的起点,并把将要画出的线条以及线条对应的属性封装成字典添加到显示栈中,代码如下

 1 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 2 {
 3     //新建贝塞斯曲线
 4     self.bezier = [UIBezierPath bezierPath];
 5
 6     //获取触摸的点
 7     UITouch *myTouche = [touches anyObject];
 8     CGPoint point = [myTouche locationInView:self];
 9
10     //把刚触摸的点设置为bezier的起点
11     [self.bezier moveToPoint:point];
12
13     //把每条线存入字典中
14     NSMutableDictionary *tempDic = [[NSMutableDictionary alloc] initWithCapacity:3];
15     [tempDic setObject:self.color forKey:@"color"];
16     [tempDic setObject:[NSNumber numberWithFloat:self.lineWidth] forKey:@"lineWidth"];
17     [tempDic setObject:self.bezier forKey:@"line"];
18
19     //把线加入数组中
20     [self.allLine addObject:tempDic];
21
22 }

      (5)当移动也就是划线的时候把点存储到BezierPath中,代码如下

 1 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
 2 {
 3     UITouch *myTouche = [touches anyObject];
 4     CGPoint point = [myTouche locationInView:self];
 5
 6     [self.bezier addLineToPoint:point];
 7
 8     //重绘界面
 9     [self setNeedsDisplay];
10
11 }

      (6)画出线条

 1 // Only override drawRect: if you perform custom drawing.
 2 // An empty implementation adversely affects performance during animation.
 3 - (void)drawRect:(CGRect)rect
 4 {
 5     //对之前的线的一个重绘过程
 6     for (int i = 0; i < self.allLine.count; i ++)
 7     {
 8         NSDictionary *tempDic = self.allLine[i];
 9         UIColor *color = tempDic[@"color"];
10         CGFloat width = [tempDic[@"lineWidth"] floatValue];
11         UIBezierPath *path = tempDic[@"line"];
12
13         [color setStroke];
14         [path setLineWidth:width];
15         [path stroke];
16     }
17
18 }

  二.画图板的使用

    上面是封装画图板要用到的全部代码,下面的代码就是如何在ViewController中使用我们的画图板了,如何实例化控件,以及控件的初始化,注册回调等在这就不做赘述了,下面给出了主要控件的回调方法

    1、通过Slider来调节线条的宽度

1 //通过slider来设置线条的宽度
2 - (IBAction)sliderChange:(id)sender
3 {
4     self.myView.lineWidth = self.mySlider.value;
5 }

  

    2、通过SegmentControl来设置线条的颜色

 1 /通过segmentControl来设置线条的颜色
 2 - (IBAction)tapSegment:(id)sender {
 3
 4     switch (self.mySegment.selectedSegmentIndex) {
 5         case 0:
 6             self.myView.color = [UIColor redColor];
 7             break;
 8         case 1:
 9             self.myView.color = [UIColor blackColor];
10             break;
11         case 2:
12             self.myView.color = [UIColor greenColor];
13             break;
14
15         default:
16             break;
17     }
18
19 }

    3、undo和redo操作

 1 //Undo
 2 - (IBAction)tapBack:(id)sender {
 3     [self.myView backImage];
 4 }
 5
 6
 7 //Redo操作
 8 - (IBAction)tapGo:(id)sender {
 9     [self.myView forwardImage];
10 }

    4.保存操作,也许下面的保存操作在处理方式上略显笨拙,如有更好的解决方案请留言。 保存的时候我是先截了个屏,然后把白板进行切割,把切割后图片存入到相册中,代码如下:

 1 //把画的图保存到相册
 2 - (IBAction)tapSave:(id)sender {
 3     //截屏
 4     UIGraphicsBeginImageContext(self.view.bounds.size);
 5     [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
 6     UIImage *uiImage = UIGraphicsGetImageFromCurrentImageContext();
 7     UIGraphicsEndImageContext();
 8
 9
10     //截取画图版部分
11     CGImageRef sourceImageRef = [uiImage CGImage];
12     CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, CGRectMake(36, 6, 249, 352));
13     UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
14
15     //把截的屏保存到相册
16     UIImageWriteToSavedPhotosAlbum(newImage , nil, nil, nil);
17
18     //给个保存成功的反馈
19     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"存储照片成功"
20                                                     message:@"您已将照片存储于图片库中,打开照片程序即可查看。"
21                                                    delegate:self
22                                           cancelButtonTitle:@"OK"
23                                           otherButtonTitles:nil];
24     [alert show];
25
26 }

  以上就是本画图板的主要代码了,有不足之处还望批评指正。转载请注明出处。在本文结束时在来几张截图吧(demo下载地址:http://www.pgyer.com/LTQ8):

时间: 2024-10-09 23:20:58

iOS开发之画图板(贝塞尔曲线)的相关文章

我的iOS开发系列博文

之前目录性的总结了发表过的关于OC方面的文章,今天在目录性的总结一下有关iOS开发的文章.走过路过不要错过哦,今天的博文也全都是干货.写技术博客与大家交流一下思想也是不错的. 下面是我的技术博客中有关iOS开发的内容,有初级部分也有高级部分,有旧的东西,也有新的东西.咸蛋就先扯到这儿,正文走起: 我的iOS系列博文如下:   01.iOS开发之简单音频播放器 02.iOS开发之视图和视图控制器 03.iOS开发之绝对布局和相对布局(屏幕适配) 04.iOS开发之自动布局显示网络请求内容 05.i

iOS开发 贝塞尔曲线的使用总结

iOS开发 贝塞尔曲线UIBezierPath 最近项目中需要用到用贝塞尔曲线去绘制路径 ,然后往路径里面填充图片,找到这篇文章挺好,记录下来 自己学习! 转至 http://blog.csdn.net/guo_hongjun1611/article/details/7839371 使用UIBezierPath类可以创建基于矢量的路径,这个类在UIKit中.此类是Core Graphics框架关于path的一个封装.使用此类可以定义简单的形状,如椭圆或者矩形,或者有多个直线和曲线段组成的形状.

IOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)(转)

Graphics Context是图形上下文,可以将其理解为一块画布,我们可以在上面进行绘画操作,绘制完成后,将画布放到我们的view中显示即可,view看作是一个画框. 自己学习时实现的demo,希望对大家有帮助,具体的实现看代码,并有完美的注释解释,还有一些对我帮助的博文供大家参考.都在代码里面. 看一下demo效果图先: 自定义CustomView类,CustomView.h: [cpp]  view plain copy #import <UIKit/UIKit.h> #import 

iOS开发 贝塞尔曲线UIBezierPath(2)

使用CAShapeLayer与UIBezierPath可以实现不在view的drawRect方法中就画出一些想要的图形 . 1:UIBezierPath: UIBezierPath是在 UIKit 中的一个类,继承于NSObject,可以创建基于矢量的路径.此类是Core Graphics框架关于path的一个OC封装.使用此类可以定义常见的圆形.多边形等形状 .我们使用直线.弧(arc)来创建复杂的曲线形状.每一个直线段或者曲线段的结束的地方是下一个的开始的地方.每一个连接的直线或者曲线段的集

iOS开发 贝塞尔曲线UIBezierPath

使用UIBezierPath类可以创建基于矢量的路径,这个类在UIKit中.此类是Core Graphics框架关于path的一个封装.使用此类可以定义简单的形状,如椭圆或者矩形,或者有多个直线和曲线段组成的形状. 1.Bezier Path 基础 UIBezierPath对象是CGPathRef数据类型的封装.path如果是基于矢量形状的,都用直线和曲线段去创建.我们使用直线段去创建矩形和多边形,使用曲线段去创建弧(arc),圆或者其他复杂的曲线形状.每一段都包括一个或者多个点,绘图命令定义如

(转) IOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)

首先了解一下CGContextRef: An opaque type that represents a Quartz 2D drawing environment. Graphics Context是图形上下文,可以将其理解为一块画布,我们可以在上面进行绘画操作,绘制完成后,将画布放到我们的view中显示即可,view看作是一个画框. 自己学习时实现的demo,希望对大家有帮助,具体的实现看代码,并有完美的注释解释,还有一些对我帮助的博文供大家参考.都在代码里面. 看一下demo效果图先: 自

iOS开发核心动画之画图板

1. 效果图 2. 用一个View来描述画图板,给画图板添加拖动的手势 // 从xib中加载 - (void)awakeFromNib { [self setUpGesture]; } // 代码创建 - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self setUpGesture]; } return self; } // 初始化添加拖动手势 - (void)se

iOS 使用贝塞尔曲线绘制路径

使用贝塞尔曲线绘制路径 大多数时候,我们在开发中使用的控件的边框是矩形,或者做一点圆角,是使得矩形的角看起来更加的圆滑. 但是如果我们想要一个不规则的图形怎么办?有人说,叫UI妹子做,不仅省事,还可以趁机接近她们(_:D).这又时候确实可以.但是如果是一个时刻变动的不规则图形,这样如果做成动图或者剪出很多张图,再叫UI妹子做的话,似乎也能解决, 但是实际效果吧,呵呵. 更重要的是从此以后UI妹子不仅不愿搭理你,连以后接触的机会都不会再给你了.好吧,iOS中我们其实不需要担心这个问题.使用UIBe

Android笔记二十九. 一款简易画图板开发

一款简易画图板开发 转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.画图板原理 1.直线效果 画图板表面上看起来可以随用户在触摸屏上自由的绘制任意图形,但是实际上当用户在触摸屏上移动时,两次拖动事件发生点的距离很小,多条极短的直线连接起来我们肉眼看起来就是直接了.在触摸屏绘制图形时,每条直线都是从上一次拖动事件发生点画到本次拖动事件的发生点,可以借助于Android提供的Path类来实现.然后,如果程序每次都是从上次拖动事件的发生点绘一条