码迷,mamicode.com
首页 > 移动开发 > 详细

iOS 画板的实现,具有颜色、线宽、橡皮、撤销和清屏功能

时间:2015-08-08 09:12:03      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:ios开发   画板   mvc   


完成一个简单的画板,能够实现画板颜色和线宽的选择,以及橡皮功能,撤销前一步的操作,和清屏功能。
效果图:
技术分享


工程下载:github工程下载链接


主要应用MVC模式进行代码架构,每一部分的代码实现思路在各部分的代码前面。


Controller
控制器实现基本思路:
1、添加工具栏和画板
2、ToolView中block的定义,colorBlock,widthBlock就是设置drawView的color;eraseBlock就设置其lineWidth和lineColor的具体值;undoBlock,clearBlock调用DrawView的函数

#import "ViewController.h"
#import "ToolView.h"
#import "DrawView.h"

#define Zwidth [UIScreen mainScreen].bounds.size.width
#define Zheight [UIScreen mainScreen].bounds.size.height

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
//    工具栏的实现
    ToolView *topView = [[ToolView alloc] initWithFrame:CGRectMake(0, 20, Zwidth, 130)];
    topView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:topView];

//    画板的实现
    DrawView *drawView = [[DrawView alloc] initWithFrame:CGRectMake(0, 150, 375, Zheight-170)];
    drawView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:drawView];

//    BLOCK的实现
    topView.colorBlock = ^(UIColor *color){
        drawView.lineColor = color;
    };

     topView.widthBlock = ^(CGFloat width){
        drawView.lineWidth = width;
    };

    topView.eraserBlock = ^(void){
        drawView.lineWidth = 20;
        drawView.lineColor = [UIColor whiteColor];
    };

    topView.undoBlock = ^{
        [drawView undoAction];
    };

    topView.clearBlock = ^{
        [drawView clearAction];

    };
}

View

ToolView.h

工具栏实现的基本思路:
1、功能选择,颜色选择,线宽选择等,都是将不同选择的button添加到view上面,并且添加动作
2、为了更高效循环添加button,动作响应根据tag来判断是哪个button,从而做出不同的响应
3、功能选择动作响应:不同的button响应不同的block
4、颜色和线宽响应:不同的button响应后设置颜色/线宽
5、添加一个背景图片,当选择某一个button时,这个图片也会移动到该button上方(block来实现)

#import <UIKit/UIKit.h>

typedef void (^ColorSelectBlock)(UIColor *color);
typedef void (^WidthSelectBlock)(CGFloat width);
typedef void (^OtherSelectBlock)(void);

@interface ToolView : UIView
{
    UIView *colorView;
    UIView *widthView;

    NSDictionary *_colorDic;    //可以用数组来实现

    UIImageView *bgImageView;
    UIImageView *widthBgImageView;
    UIImageView *colorBgImageView;
}

@property (nonatomic,copy) ColorSelectBlock colorBlock;
@property (nonatomic,copy) WidthSelectBlock widthBlock;
@property (nonatomic,copy) OtherSelectBlock eraserBlock;
@property (nonatomic,copy) OtherSelectBlock undoBlock;
@property (nonatomic,copy) OtherSelectBlock clearBlock;

@end

ToolView.m

#import "ToolView.h"

#define Zwidth [UIScreen mainScreen].bounds.size.width
#define Zheight [UIScreen mainScreen].bounds.size.height

@implementation ToolView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self _creatButtonView];
        [self _creatColorView];
        [self _creatWidthView];
    }
    return self;
}

//工具选择的实现
- (void)_creatButtonView {
    CGFloat buttonwWidth = Zwidth/5;
    CGFloat buttonHeight = 50;

    NSArray *nameArray = @[@"颜色",@"线宽",@"橡皮",@"撤销",@"清屏"];
    for (int i = 0; i < 5; i++) {
        CGRect frame = CGRectMake(i*buttonwWidth, 0, buttonwWidth, buttonHeight);
        UIButton *button = [[UIButton alloc] initWithFrame:frame];
        [button setTitle:nameArray[i] forState:UIControlStateNormal];
        button.backgroundColor = [UIColor lightGrayColor];
        button.tag = i+100;
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:button];
    }

//    选择动画的添加
    bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, buttonwWidth, buttonHeight)];
    bgImageView.backgroundColor = [UIColor cyanColor];
    bgImageView.alpha = 0.3;
    [self addSubview:bgImageView];
}

//宽度选择视图的实现
- (void)_creatWidthView {
    widthView = [[UIView alloc] initWithFrame:CGRectMake(0, 55, Zwidth, 70)];
    widthView.backgroundColor = [UIColor brownColor];
    [self addSubview:widthView];
    widthView.hidden = YES;

//    添加button
    CGFloat widthWidth = Zwidth/7;
    CGFloat widthHeight = 70;

    NSArray *widthArray = @[@"1点",@"3点",@"5点",@"8点",@"10点",@"15点",@"20点"];
    for (int i = 0; i < 7; i++) {
        CGRect frame = CGRectMake(i*widthWidth, 0, widthWidth, widthHeight);
        UIButton *button = [[UIButton alloc] initWithFrame:frame];
        [button setTitle:widthArray[i] forState:UIControlStateNormal];
        button.backgroundColor = [UIColor lightGrayColor];
        button.tag = i+200;
        [button addTarget:self action:@selector(widthbuttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [widthView addSubview:button];
    }

//    选择动画的添加
    widthBgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, widthWidth, widthHeight)];
    widthBgImageView.backgroundColor = [UIColor cyanColor];
    widthBgImageView.alpha = 0.3;
    [widthView addSubview:widthBgImageView];
}

- (void)_creatColorView {
    colorView = [[UIView alloc] initWithFrame:CGRectMake(0, 55, Zwidth, 70)];
    colorView.backgroundColor = [UIColor lightGrayColor];
    [self addSubview:colorView];
    colorView.hidden = NO;

    CGFloat colorWidth = (Zwidth-45)/9;
    CGFloat colorHeight = 70;
    _colorDic = @{@"0" : [UIColor grayColor],    @"1" : [UIColor redColor],
                  @"2" : [UIColor greenColor],   @"3" : [UIColor blueColor],
                  @"4" : [UIColor yellowColor],  @"5" : [UIColor orangeColor],
                  @"6" : [UIColor purpleColor],  @"7" : [UIColor brownColor],
                  @"8" : [UIColor blackColor]};
    for (int i = 0; i < 9; i++) {
        NSString *str = [NSString stringWithFormat:@"%i",i];
        UIColor *color = _colorDic[str];

        CGRect frame = CGRectMake(i*(colorWidth+5), 0, colorWidth, colorHeight);
        UIButton *colorBtn = [[UIButton alloc] initWithFrame:frame];
        colorBtn.backgroundColor = color;
        colorBtn.tag = 300+i;
        [colorBtn addTarget:self  action:@selector(colorButtonAction:) forControlEvents:UIControlEventTouchUpInside];
        [colorView addSubview:colorBtn];
    }

    colorBgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, colorWidth, colorHeight)];
    colorBgImageView.backgroundColor = [UIColor cyanColor];
    colorBgImageView.alpha = 0.2;
    [colorView addSubview:colorBgImageView];
}

//工具栏选择按钮Action实现
- (void)buttonAction:(UIButton *)btn{
    if (btn.tag == 100) {
        colorView.hidden = NO;
        widthView.hidden = YES;
    }else if (btn.tag == 101) {
        colorView.hidden = YES;
        widthView.hidden = NO;
    }else if (btn.tag == 103){
        if (self.undoBlock) {
            self.undoBlock();
        }
    }else if (btn.tag == 104) {
        if (self.clearBlock) {
            self.clearBlock();
        }
    }else {
        if (self.eraserBlock) {
            self.eraserBlock();
        }
    }

    [UIView animateWithDuration:0.3 animations:^{
        bgImageView.center = btn.center;
    }];    
}

//线宽选择按钮Action实现
- (void)widthbuttonAction:(UIButton *)btn {
    if (btn.tag <= 202 ) {
        if (_widthBlock) {
            _widthBlock((btn.tag-200)*2+1);
        }
    }else if(btn.tag <= 205) {
        if (_widthBlock) {
            _widthBlock(btn.tag-195);
        }
    }else {
        if (_widthBlock) {
            _widthBlock(btn.tag*5-1015);
        }
    }

    [UIView animateWithDuration:0.3 animations:^{
        widthBgImageView.center = btn.center;
    }];
}

//颜色选择按钮Action的实现
- (void)colorButtonAction:(UIButton *)btn {
    NSInteger i = btn.tag-300;
    NSString *str = [NSString stringWithFormat:@"%li",i];
    if (_colorBlock) {
        _colorBlock(_colorDic[str]);
    }

    [UIView animateWithDuration:0.3 animations:^{
        colorBgImageView.center = btn.center;
    }];
}

画板:

DrawView.h

画板实现的基本思路:
1、当touchesBegan时,创建路径,并将该点作为路径的起始点;
2、当touchesMove时,不断在该路径上添加line,调用[self setNeedsDisplay]
3、当touchesEnd时,将path作为modal的一个成员变量保存在modal中,此次的modal放在PathModalArray中,释放路径
4、drawRect绘制路径时,不仅要画这次的路径,还要画之前的路径,就是遍历pathModalArray来调用
5、撤销动作undoAction,即移除pathModalArray中的最后一个object,并且调用[self setNeedsDisplay]
6、清屏动作clearAction,即移除pathModalArray中的所有object,并且调用[self setNeedsDisplay]

#import <UIKit/UIKit.h>

@interface DrawView : UIView
{
    CGMutablePathRef path;
    NSMutableArray *pathModalArray;
}

@property (nonatomic,strong) UIColor *lineColor;
@property (nonatomic,assign) CGFloat lineWidth;

- (void)undoAction;
- (void)clearAction;

@end

DrawView.m

#import "DrawView.h"
#import "PathModal.h"

@implementation DrawView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        pathModalArray = [NSMutableArray array];
        self.lineColor = [UIColor blackColor];
        self.lineWidth = 8.0;
        self.backgroundColor = [UIColor whiteColor];
        self.userInteractionEnabled = YES;
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    for (PathModal *modal in pathModalArray) {
        CGContextRef context = UIGraphicsGetCurrentContext();

        [modal.color setStroke];
        CGContextSetLineWidth(context, modal.width);
        CGContextAddPath(context, modal.path);

        CGContextDrawPath(context, kCGPathStroke);
    }

    if (path != nil) {
        CGContextRef context = UIGraphicsGetCurrentContext();

        CGContextAddPath(context, path);

        [self.lineColor setStroke];
        CGContextSetLineWidth(context, self.lineWidth);

        CGContextDrawPath(context, kCGPathStroke);

    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];

    path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, p.x, p.y);
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];

    //点加至线上
    CGPathAddLineToPoint(path, NULL, p.x, p.y);
    //移动->重新绘图
    [self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    PathModal *modal = [[PathModal alloc] init];
    modal.color = self.lineColor;
    modal.width = self.lineWidth;
    modal.path = path;

    [pathModalArray addObject:modal];
    CGPathRelease(path);
    path = nil;
}

- (void)undoAction {
    [pathModalArray removeLastObject];
    [self setNeedsDisplay];
}

- (void)clearAction {
    [pathModalArray removeAllObjects];
    [self setNeedsDisplay];
}

Modal

PathModal.h

数据:存储每一次的路径,宽度和颜色。

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface PathModal : NSObject

@property (nonatomic,strong) UIColor *color;
@property (nonatomic,assign) CGFloat width;
@property (nonatomic,assign) CGMutablePathRef path;


@end

PathModal.m

#import "PathModal.h"

@implementation PathModal

- (void)dealloc {
    CGPathRelease(_path);
}

- (void)setPath:(CGMutablePathRef)path {
    if (_path != path) {
        _path = (CGMutablePathRef)CGPathRetain(path);    
    }
}
@end

版权声明:本文为博主原创文章,未经博主允许不得转载。

iOS 画板的实现,具有颜色、线宽、橡皮、撤销和清屏功能

标签:ios开发   画板   mvc   

原文地址:http://blog.csdn.net/zsk_zane/article/details/47354781

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!