完成一个简单的画板,能够实现画板颜色和线宽的选择,以及橡皮功能,撤销前一步的操作,和清屏功能。
效果图:
工程下载: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
版权声明:本文为博主原创文章,未经博主允许不得转载。