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



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

效果图:



工程下载: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

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

时间: 2024-10-05 10:36:51

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

【iOS开发-85】利用touch触摸事件:实现画板画画、撤销、清屏以及图片保存功能

(1)效果 (2)代码下载 http://download.csdn.net/detail/wsb200514/8251841 (3)总结 --最主要的"画"的功能是在drawRect函数中完成,而所有路径或者点得拼接是在touchesBegan.touchesMoved和touchesEnded三个函数中完成的. --每次修改后记得要setNeedsDisplay刷新. --可以记录每个CGPoint点,然后用CGContextRef上下文画出来. --也可以开启一个UIBezier

几何画板中更改背景颜色的方法有哪些

在使用几何画板的过程的,大家发现背景颜色默认为白色,但是有时为了让我们做的图形的效果更加美观或更方便对比,就需要更改背景颜色.但是一些用户对于这种操作还不是很了解,因此,我们特地制作了这篇相关教程,希望可以帮到大家.这就给大家分享一下几何画板中更改背景颜色的方法有哪些?  几何画板保存画板文件 在几何画板中更改背景颜色的步骤: 步骤一.点击编辑->参数选项,打开“参数选项对话框”.  几何画板参数选项 步骤二.点击颜色->背景颜色,选择合适的颜色.  几何画板颜色选择器 步骤三.选择颜色后,首

Qt ,mac osx ios x11 高清屏,视网膜的支持

Qt 5.0中添加了对于retina显示的基本支持.即将到来的Qt 5.1中提供了新的API和缺陷修复,对于这一问题进行了改进.Qt 4.8也获得了良好的支持,我们反向移植了一些Qt 5的补丁. 尽管这些实现的努力和Mac以及iOS程序员最为相关,但是来看一看其它平台是如何处理高DPI显示这一问题,也是很有趣的.这里主要有两种方式: 基于DPI缩放--Win32 GDI和KDE.在这种方式中,应用程序在全物理设备分辨率下工作,使用系统提供的一个DPI设定或者缩放因子,用于缩放布局.字体通常会被操

ios程序,顶部和底部产生空白——程序不能全屏运行

在开发过程中,遇到过这样的问题,整个程序不能以全屏状态运行,顶部和底部出现空白,如下图所示: 这样的原因是:设置的启动页不合适,设置大小合适的启动页就好了 ios程序,顶部和底部产生空白--程序不能全屏运行

【转】具透 | 你可能不知道,iOS 10 有一个中国「特供」的联网权限功能

9 月底,苹果正式在北京成立了苹果中国研发中心.近几年,我们也在每年更新的 iOS 系统中不断看到,苹果对中国市场的关照.从早前的九宫格输入法,到最近的骚扰电话拦截,都照顾了国内用户的需求. 在 iOS 10 中,除了 骚扰电话识别和拦截 功能的加入,苹果其实还专为国行 iPhone 制定了一个「联网权限」功能1. 它是什么 相信已有不少人早就注意到这个功能.毕竟在 iOS 10 中,每当你打开一个新安装的 App 时,应用除了可能会弹出请求授权访问相册.推送通知.获取定位这些熟悉的权限之外,还

iOS的录屏功能

iOS的录屏功能其实没什么好说的,因为网上的教程很多,但是网上的Demo无一例外几乎都有一个bug,那就是iPad上会出现闪退,这也体现了国内的教程文档的一个特点,就是抄袭,教程几乎千篇一律,bug也是一摸一样,经过多次测试,终于找着了解决方案. 废话少说,代码献上. //开始录屏 extern "C" void startRecord() { NSLog(@"开始录屏"); if ([RPScreenRecorder sharedRecorder].isRecor

iOS开发-16进制颜色转换

项目中经常会用到颜色转换,有的是通过十六进制转成数字转颜色,想简单的点直接通过字符串转一下,简单扩展了一下分类UIColor,代码如下: +(UIColor *)colorWithHex:(NSString *)hexColor{ return [self colorWithHex:hexColor alpha:1.0f]; } //http://www.cnblogs.com/xiaofeixiang iOS技术交流:228407086 +(UIColor *)colorWithHex:(NS

ios修改NavigationController的背景颜色

在ios开发的过程中,我们经常需要修改NavigationController的背景颜色,当使用方法[self.navigationController.navigationBar setBackgroundColor:[UIColor redColor]]时,运行的结果并不能修改北京颜色: 现在提供一种新方法来解决这个问题: 写一个NavigationBar写一个类别: @interface UINavigationBar (BackgroundColor) //设置navigationBar

ios 修改导航栏的颜色

UINavigationBar *bar = [UINavigationBar appearance]; [bar setBarTintColor:[UIColor blueColor]]; // 修改导航栏的颜色为蓝色 [bar setBarStyle:UIBarStyleBlack]; [bar setTintColor:[UIColor whiteColor]]; // 字体的颜色为白色 [bar setTranslucent:NO];