iOS - Quartz 2D 画板绘制
生活随笔
收集整理的这篇文章主要介绍了
iOS - Quartz 2D 画板绘制
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
1、绘制画板
1.1 绘制简单画板
PaintBoardView.h
@interface PaintBoardView : UIView@endPaintBoardView.m
@interface PaintBoardView ()/// 路径@property (nonatomic, strong) UIBezierPath *path;/// 保存所有路径的数组@property (nonatomic, strong) NSMutableArray *pathsArrayM;@end@implementation PaintBoardView/// 初始化- (instancetype)initWithFrame:(CGRect)frame {if (self = [super initWithFrame:frame]) {self.backgroundColor = [UIColor whiteColor];}return self;}/// 触摸开始- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {// 获取触摸起始点位置CGPoint startPoint = [touches.anyObject locationInView:self];// 添加路径描绘起始点[self.path moveToPoint:startPoint];// 添加一条触摸路径描绘[self.pathsArrayM addObject:self.path];}/// 触摸移动- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {// 获取触摸点位置CGPoint touchPoint = [touches.anyObject locationInView:self];// 添加路径描绘[self.path addLineToPoint:touchPoint];// 刷新视图[self setNeedsDisplay];}/// 触摸结束- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {// 获取绘制结果UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);CGContextRef ctx = UIGraphicsGetCurrentContext();[self.layer renderInContext:ctx];UIImage *image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();NSData *data = UIImagePNGRepresentation(image);[data writeToFile:@"/Users/JHQ0228/Desktop/Images/pic.png" atomically:YES];}/// 触摸取消- (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event {[self touchesEnded:touches withEvent:event];}/// 绘制图形- (void)drawRect:(CGRect)rect {for (UIBezierPath *path in self.pathsArrayM) {// 绘制路径[path stroke];}}/// 懒加载- (UIBezierPath *)path {if (_path == nil) {_path = [UIBezierPath bezierPath];}return _path;}- (NSMutableArray *)pathsArrayM {if (_pathsArrayM == nil) {_pathsArrayM = [NSMutableArray array];}return _pathsArrayM;}@endViewController.m
// 创建画板CGRect frame = CGRectMake(20, 50, self.view.bounds.size.width - 40, 200);PaintBoardView *paintBoard = [[PaintBoardView alloc] initWithFrame:frame];[self.view addSubview:paintBoard];效果
1.2 绘制画板封装
具体实现代码见 GitHub 源码 QExtension
QPaintBoardPath.h
@interface QPaintBoardPath : UIBezierPath/// 线的颜色@property (nonatomic, strong) UIColor *pathColor;/// 线的宽度@property (nonatomic, assign) CGFloat pathWidth;@endQPaintBoardPath.m
@implementation QPaintBoardPath@endQPaintBoardView.h
@interface QPaintBoardView : UIView/// 画线的宽度,default is 1,max is 30@property (nonatomic, assign) CGFloat paintLineWidth;/// 画笔的颜色,default is blackColor@property (nonatomic, strong) UIColor *paintLineColor;/// 画板的颜色,default is whiteColor@property (nonatomic, strong) UIColor *paintBoardColor;/*** 创建画板视图控件,获取绘画结果** @param frame 画板视图控件 frame* @param lineWidth 画笔的线宽,default is 1,max is 30* @param lineColor 画笔的颜色,default is blackColor* @param boardColor 画板的颜色,default is whiteColor* @param result 绘画结果** @return 手势锁视图控件*/+ (instancetype)q_paintBoardViewWithFrame:(CGRect)framelineWidth:(CGFloat)lineWidthlineColor:(nullable UIColor *)lineColorboardColor:(nullable UIColor *)boardColorpaintResult:(void (^)(UIImage * _Nullable image))result;/*** 创建简单画板视图控件** @param frame 画板视图控件 frame** @return 手势锁视图控件*/+ (instancetype)q_paintBoardViewWithFrame:(CGRect)frame;/*** 获取绘画结果** @return 绘画结果图片*/- (UIImage * _Nullable)q_getPaintImage;/*** 清除绘画结果*/- (void)q_clear;/*** 撤销绘画结果*/- (void)q_back;@endQPaintBoardView.m
#import "QPaintBoardPath.h"@interface QPaintBoardView ()/// 路径@property (nonatomic, strong, nullable) QPaintBoardPath *path;/// 保存所有路径的数组@property (nonatomic, strong) NSMutableArray *pathsArrayM;/// 绘画结果@property (nonatomic, copy) void (^resultBlock)(UIImage * _Nullable);/// 按钮工具条@property (nonatomic, strong) UIView *toolView;/// 画笔设置视图@property (nonatomic, strong) UIView *brushSetingView;/// 颜色选择视图@property (nonatomic, strong) UIScrollView *colorSelectedView;/// 画板设置视图@property (nonatomic, strong) UIScrollView *boardSetingView;/// 记录线的颜色@property (nonatomic, strong) UIColor *lastPaintLineColor;/// 记录线的宽度@property (nonatomic, assign) CGFloat lastPaintLineWidth;@end@implementation QPaintBoardView#pragma mark - 创建画板/// 创建画板视图控件,获取绘画结果+ (instancetype)q_paintBoardViewWithFrame:(CGRect)framelineWidth:(CGFloat)lineWidthlineColor:(nullable UIColor *)lineColorboardColor:(nullable UIColor *)boardColorpaintResult:(void (^)(UIImage * _Nullable image))result {QPaintBoardView *paintBoardView = [[self alloc] init];// CGRect tmpFrame = frame;// tmpFrame.size.height = frame.size.height + 44;paintBoardView.frame = frame;paintBoardView.paintLineWidth = (lineWidth > 30 ? 30 : lineWidth) ? : 1;paintBoardView.paintLineColor = lineColor ? : [UIColor blackColor];paintBoardView.paintBoardColor = boardColor ? : [UIColor whiteColor];paintBoardView.resultBlock = result;return paintBoardView;}/// 创建简单画板视图控件+ (instancetype)q_paintBoardViewWithFrame:(CGRect)frame {QPaintBoardView *paintBoardView = [[self alloc] initWithFrame:frame];paintBoardView.paintLineWidth = 1;paintBoardView.paintLineColor = [UIColor blackColor];paintBoardView.paintBoardColor = [UIColor whiteColor];return paintBoardView;}#pragma mark - 自定义画板/// 初始化,自定义画板界面- (instancetype)init {if (self = [super init]) {self.clipsToBounds = YES;// 添加工具按钮视图self.toolView = [[UIView alloc] init];self.toolView.backgroundColor = [UIColor blackColor];[self addSubview:self.toolView];NSArray *imageNames = @[@"btn_brush", @"btn_board", @"btn_eraser", @"btn_back", @"btn_clear", @"btn_save"];NSArray *selectedImageNames = @[@"btn_brush_pressed", @"btn_board_pressed", @"btn_eraser_pressed"];for (NSUInteger i = 0; i < 6; i++) {UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];button.tag = i;[button setBackgroundImage:[self q_getBundleImageWithName:imageNames[i]] forState:UIControlStateNormal];[button addTarget:self action:@selector(toolButtonClick:) forControlEvents:UIControlEventTouchUpInside];[self.toolView addSubview:button];if (i < 3) {[button setBackgroundImage:[self q_getBundleImageWithName:selectedImageNames[i]] forState:UIControlStateSelected];}}// 添加画笔设置视图self.brushSetingView = [[UIView alloc] init];self.brushSetingView.backgroundColor = [UIColor grayColor];[self addSubview:self.brushSetingView];[self sendSubviewToBack:self.brushSetingView];UIView *widthBackView = [[UIView alloc] init];widthBackView.layer.borderWidth = 1;widthBackView.layer.borderColor = [UIColor lightGrayColor].CGColor;UIView *widthView = [[UIView alloc] init];[widthBackView addSubview:widthView];[self.brushSetingView addSubview:widthBackView];UISlider *widthSlider = [[UISlider alloc] init];widthSlider.thumbTintColor = [UIColor orangeColor];[widthSlider addTarget:self action:@selector(widthSliderClick:) forControlEvents:UIControlEventValueChanged];[self.brushSetingView addSubview:widthSlider];UIButton *colorSelectedBtn = [[UIButton alloc] init];colorSelectedBtn.layer.borderWidth = 1;colorSelectedBtn.layer.borderColor = [UIColor lightGrayColor].CGColor;[colorSelectedBtn addTarget:self action:@selector(colorSelectedBtnClick:) forControlEvents:UIControlEventTouchUpInside];[self.brushSetingView addSubview:colorSelectedBtn];// 添加画笔颜色选择视图self.colorSelectedView = [[UIScrollView alloc] init];self.colorSelectedView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.3];self.colorSelectedView.showsHorizontalScrollIndicator = NO;[self addSubview:self.colorSelectedView];[self sendSubviewToBack:self.colorSelectedView];NSArray *colorArray = @[[UIColor blackColor], [UIColor whiteColor], [UIColor redColor],[UIColor greenColor], [UIColor blueColor], [UIColor cyanColor],[UIColor magentaColor], [UIColor orangeColor], [UIColor yellowColor],[UIColor darkGrayColor], [UIColor lightGrayColor], [UIColor brownColor],[UIColor grayColor], [UIColor purpleColor]];for (NSUInteger i = 0; i < 14; i++) {UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];button.layer.borderWidth = 1;button.layer.borderColor = [UIColor lightGrayColor].CGColor;[button setBackgroundColor:colorArray[i]];[button addTarget:self action:@selector(colorSelectedClick:) forControlEvents:UIControlEventTouchUpInside];[self.colorSelectedView addSubview:button];}// 添加画板设置视图self.boardSetingView = [[UIScrollView alloc] init];self.boardSetingView.backgroundColor = [UIColor grayColor];self.boardSetingView.showsHorizontalScrollIndicator = NO;[self addSubview:self.boardSetingView];[self sendSubviewToBack:self.boardSetingView];for (NSUInteger i = 0; i < 14; i++) {UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];button.layer.borderWidth = 1;button.layer.borderColor = [UIColor lightGrayColor].CGColor;[button setBackgroundColor:colorArray[i]];[button addTarget:self action:@selector(boardColorSelectedClick:) forControlEvents:UIControlEventTouchUpInside];[self.boardSetingView addSubview:button];}}return self;}/// 布局子控件- (void)layoutSubviews {[super layoutSubviews];if (self.subviews.count) {// 设置工具按钮视图self.toolView.frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 44);for (NSUInteger i = 0; i < 6; i++) {CGFloat margin = (self.bounds.size.width - 44 * 6) / 7;CGFloat x = margin + (margin + 44) * i;self.toolView.subviews[i].frame = CGRectMake(x, 0, 44, 44);}// 设置画笔设置视图self.brushSetingView.frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60);self.brushSetingView.subviews[0].frame = CGRectMake(15, 15, 30, 30);self.brushSetingView.subviews[0].layer.cornerRadius = 15;self.brushSetingView.subviews[0].layer.masksToBounds = YES;CGFloat w = self.paintLineWidth;self.brushSetingView.subviews[0].subviews[0].frame = CGRectMake(15 - w / 2, 15 - w / 2, w, w);self.brushSetingView.subviews[0].subviews[0].layer.cornerRadius = w / 2;self.brushSetingView.subviews[0].subviews[0].layer.masksToBounds = YES;self.brushSetingView.subviews[0].subviews[0].backgroundColor = self.paintLineColor;self.brushSetingView.subviews[1].frame = CGRectMake(60, 15, self.bounds.size.width - 60 - 80, 32);UISlider *slider = self.brushSetingView.subviews[1];slider.value = self.paintLineWidth / 30;self.brushSetingView.subviews[2].frame = CGRectMake(self.bounds.size.width - 60, 15, 50, 30);self.brushSetingView.subviews[2].backgroundColor = self.paintLineColor;// 设置画笔颜色选择视图self.colorSelectedView.frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60);self.colorSelectedView.contentSize = CGSizeMake(14 * (50 + 20) + 20, 50);for (NSUInteger i = 0; i < 14; i++) {CGFloat x = 20 + (20 + 50) * i;self.colorSelectedView.subviews[i].frame = CGRectMake(x, 10, 50, 40);}// 设置画板设置视图self.boardSetingView.frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60);self.boardSetingView.contentSize = CGSizeMake(14 * (50 + 20) + 20, 50);for (NSUInteger i = 0; i < 14; i++) {CGFloat x = 20 + (20 + 50) * i;self.boardSetingView.subviews[i].frame = CGRectMake(x, 10, 50, 40);}}}/// 工具按钮点击事件处理- (void)toolButtonClick:(UIButton *)btn {switch (btn.tag) {case 0: {// 画笔设置[self exitEraseState];if (btn.isSelected == NO) {[self hideBoardSetingView];[self showColorSelectedView];[self showBrushSetingView];} else {[self hideColorSelectedView];[self hideBrushSetingView];}break;}case 1: {// 画板设置[self exitEraseState];if (btn.isSelected == NO) {[self hideColorSelectedView];[self hideBrushSetingView];[self showBoardSetingView];} else {[self hideBoardSetingView];}break;}case 2: {// 擦除[self hideBoardSetingView];[self hideColorSelectedView];[self hideBrushSetingView];if (btn.selected == NO) {[self enterEraseState];} else {[self exitEraseState];}break;}case 3: {// 撤销[self hideBoardSetingView];[self hideColorSelectedView];[self hideBrushSetingView];[self q_back];break;}case 4: {// 清除[self hideBoardSetingView];[self hideColorSelectedView];[self hideBrushSetingView];[self exitEraseState];[self q_clear];break;}case 5: {// 获取绘制结果[self hideBoardSetingView];[self hideColorSelectedView];[self hideBrushSetingView];[self exitEraseState];if (self.resultBlock) {self.resultBlock([self q_getPaintImage]);}break;}default:break;}}/// 画笔线宽设置按钮点击事件处理- (void)widthSliderClick:(UISlider *)slider {if (slider.value == 0) {self.paintLineWidth = 1;} else {self.paintLineWidth = slider.value * 30;}CGFloat w = self.paintLineWidth;self.brushSetingView.subviews[0].subviews[0].frame = CGRectMake(15 - w / 2, 15 - w / 2, w, w);self.brushSetingView.subviews[0].subviews[0].layer.cornerRadius = w / 2;}/// 画笔颜色选择按钮点击事件处理- (void)colorSelectedBtnClick:(UIButton *)btn {if (btn.selected == NO) {[self showColorSelectedView];} else {[self hideColorSelectedView];}}/// 画笔颜色选择点击响应事件处理- (void)colorSelectedClick:(UIButton *)btn {self.paintLineColor = btn.backgroundColor;self.brushSetingView.subviews[0].subviews[0].backgroundColor = btn.backgroundColor;self.brushSetingView.subviews[2].backgroundColor = btn.backgroundColor;}/// 画板颜色选择点击响应事件处理- (void)boardColorSelectedClick:(UIButton *)btn {self.paintBoardColor = btn.backgroundColor;}/// 显示画笔设置视图- (void)showBrushSetingView {UIButton *setBrushBtn = self.toolView.subviews[0];if (setBrushBtn.selected == NO) {setBrushBtn.selected = YES;[UIView animateWithDuration:0.2 animations:^{CGRect frame = CGRectMake(0, self.bounds.size.height - 44 - 60, self.bounds.size.width, 60);self.brushSetingView.frame = frame;}];}}/// 隐藏画笔设置视图- (void)hideBrushSetingView {UIButton *setBrushBtn = self.toolView.subviews[0];if (setBrushBtn.selected) {setBrushBtn.selected = NO;[UIView animateWithDuration:0.2 animations:^{CGRect frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60);self.brushSetingView.frame = frame;}];}}// 显示画笔颜色选择视图- (void)showColorSelectedView {UIButton *colorSelectedBtn = self.brushSetingView.subviews[2];if (colorSelectedBtn.selected == NO) {colorSelectedBtn.selected = YES;[UIView animateWithDuration:0.2 animations:^{CGRect frame = CGRectMake(0, self.bounds.size.height - 44 - 60 - 60, self.bounds.size.width, 60);self.colorSelectedView.frame = frame;}];}}/// 隐藏画笔颜色选择视图- (void)hideColorSelectedView {UIButton *colorSelectedBtn = self.brushSetingView.subviews[2];if (colorSelectedBtn.selected) {colorSelectedBtn.selected = NO;[UIView animateWithDuration:0.2 animations:^{CGRect frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60);self.colorSelectedView.frame = frame;}];}}/// 显示画板设置视图- (void)showBoardSetingView {UIButton *setBoardBtn = self.toolView.subviews[1];if (setBoardBtn.selected == NO) {setBoardBtn.selected = YES;[UIView animateWithDuration:0.2 animations:^{CGRect frame = CGRectMake(0, self.bounds.size.height - 44 - 60, self.bounds.size.width, 60);self.boardSetingView.frame = frame;}];}}/// 隐藏画板设置视图- (void)hideBoardSetingView {UIButton *setBoardBtn = self.toolView.subviews[1];if (setBoardBtn.selected) {setBoardBtn.selected = NO;[UIView animateWithDuration:0.2 animations:^{CGRect frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60);self.boardSetingView.frame = frame;}];}}/// 进入擦除状态- (void)enterEraseState {UIButton *setEraseBtn = self.toolView.subviews[2];if (setEraseBtn.selected == NO) {setEraseBtn.selected = YES;self.lastPaintLineColor = self.paintLineColor;self.paintLineColor = self.paintBoardColor;self.lastPaintLineWidth = self.paintLineWidth;self.paintLineWidth = self.paintLineWidth + 5;}}/// 退出擦除状态- (void)exitEraseState {UIButton *setEraseBtn = self.toolView.subviews[2];if (setEraseBtn.isSelected) {setEraseBtn.selected = NO;self.paintLineColor = self.lastPaintLineColor;self.paintLineWidth = self.lastPaintLineWidth;}}#pragma mark - 绘制图案/// 触摸开始- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {if (self.subviews.count) {[self hideColorSelectedView];[self hideBrushSetingView];[self hideBoardSetingView];}// 获取触摸起始点位置CGPoint startPoint = [touches.anyObject locationInView:self];// 添加路径描绘起始点[self.path moveToPoint:startPoint];// 记录线的属性self.path.pathColor = self.paintLineColor;self.path.pathWidth = self.paintLineWidth;// 添加一条触摸路径描绘[self.pathsArrayM addObject:self.path];}/// 触摸移动- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {// 获取触摸点位置CGPoint touchPoint = [touches.anyObject locationInView:self];// 添加路径描绘[self.path addLineToPoint:touchPoint];// 刷新视图[self setNeedsDisplay];}/// 触摸结束- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {// 销毁 pathself.path = nil;}/// 触摸取消- (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event {[self touchesEnded:touches withEvent:event];}/// 绘制图形,只要调用 drawRect 方法就会把之前的内容全部清空- (void)drawRect:(CGRect)rect {for (QPaintBoardPath *path in self.pathsArrayM) {// 绘制路径path.lineWidth = path.pathWidth;[path.pathColor setStroke];path.lineCapStyle = kCGLineCapRound;path.lineJoinStyle = kCGLineJoinRound;[path stroke];}}/// 获取绘画结果- (UIImage * _Nullable)q_getPaintImage {UIImage *image = nil;CGSize boardSize = self.bounds.size;if (self.subviews.count) {boardSize.height = self.bounds.size.height - 44;}if (self.pathsArrayM.count) {UIGraphicsBeginImageContextWithOptions(boardSize, NO, 0);CGContextRef ctx = UIGraphicsGetCurrentContext();[self.layer renderInContext:ctx];image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();}return image;}/// 清除绘画结果- (void)q_clear {if (self.pathsArrayM.count) {[self.pathsArrayM removeAllObjects];[self setNeedsDisplay];}}/// 撤销绘画结果- (void)q_back {if (self.pathsArrayM.count) {[self.pathsArrayM removeLastObject];[self setNeedsDisplay];}}/// 懒加载- (QPaintBoardPath * _Nullable)path {// path 每次绘制完成后需要销毁,否则无法清除之前绘制的路径if (_path == nil) {_path = [QPaintBoardPath bezierPath];}return _path;}- (NSMutableArray *)pathsArrayM {if (_pathsArrayM == nil) {_pathsArrayM = [NSMutableArray array];}return _pathsArrayM;}/// 设置属性值- (void)setPaintBoardColor:(UIColor *)paintBoardColor {_paintBoardColor = paintBoardColor;self.backgroundColor = paintBoardColor;}/// 加载 bundle 中的图片- (UIImage *)q_getBundleImageWithName:(NSString *)name {NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"QPaintBoardView.bundle"];UIImage *image = [[UIImage imageWithContentsOfFile:[bundlePath stringByAppendingPathComponent:name]]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];return image;}@end1、创建简单画板
// 创建简单画板CGRect frame = CGRectMake(20, 50, self.view.bounds.size.width - 40, 200);QPaintBoardView *paintBoardView = [QPaintBoardView q_paintBoardViewWithFrame:frame];// 可选属性值设置paintBoardView.paintLineWidth = 5; // default is 1paintBoardView.paintLineColor = [UIColor redColor]; // default is blackColorpaintBoardView.paintBoardColor = [UIColor cyanColor]; // default is whiteColor[self.view addSubview:paintBoardView];self.paintBoardView = paintBoardView;// 撤销绘画结果[self.paintBoardView q_back];// 清除绘画结果[self.paintBoardView q_clear];// 获取绘画结果UIImage *image = [self.paintBoardView q_getPaintImage];效果
2、创建画板
// 创建画板QPaintBoardView *paintBoard = [QPaintBoardView q_paintBoardViewWithFrame:self.view.boundslineWidth:0lineColor:nilboardColor:nilpaintResult:^(UIImage * _Nullable image) {if (image) {NSData *data = UIImagePNGRepresentation(image);[data writeToFile:@"/Users/JHQ0228/Desktop/Images/pic.png" atomically:YES];}}];[self.view addSubview:paintBoard];效果
转载于:https://www.cnblogs.com/QianChia/p/6286346.html
总结
以上是生活随笔为你收集整理的iOS - Quartz 2D 画板绘制的全部内容,希望文章能够帮你解决所遇到的问题。