简单画板实例
制作一个简单的画板,可以绘图,可以从相册添加照片,最后可以保存到相册
界面布局如图
iOS要使用相机和相册功能,先在info.plist中配置权限
ViewController.m
#import "ViewController.h"
#import "DrawView.h"
#define RED [UIColor colorWithRed:252.0f/255 green:92.0f/255 blue:70.0f/255 alpha:1]
#define GREEN [UIColor colorWithRed:61.0f/255 green:201.0f/255 blue:42.0f/255 alpha:1]
#define BLUE [UIColor colorWithRed:25.0f/255 green:148.0f/255 blue:252.0f/255 alpha:1]
@interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate,UIGestureRecognizerDelegate>
//绑定界面中的画面View
@property (strong, nonatomic) IBOutlet DrawView *drawView;
@property (strong, nonatomic) UIView *pickerImageContainer;
@property (strong, nonatomic) UIImageView *pickerImageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//初始笔触的颜色和粗细
self.drawView.strokeColor = RED;
self.drawView.selectedLineWidth = 1;
}
//颜色按钮选择
- (IBAction)colorSelected:(UIButton *)button {
switch (button.tag) {
case 0:
self.drawView.strokeColor = RED;
break;
case 1:
self.drawView.strokeColor = GREEN;
break;
case 2:
self.drawView.strokeColor = BLUE;
break;
}
}
//笔触粗细滑块change事件
- (IBAction)lineWidthChange:(UISlider *)slider {
self.drawView.selectedLineWidth = slider.value;
}
//撤销操作,调用drawView中的undo
- (IBAction)undo:(UIBarButtonItem*)item
{
[self.drawView undo];
}
//清屏操作,调用drawView中的clearCanvas
- (IBAction)clearCanvas:(UIBarButtonItem*)item
{
[self.drawView clearCanvas];
}
//保存操作,调用drawView中的saveImage
- (IBAction)saveImage:(UIBarButtonItem*)item
{
[self.drawView saveImage];
}
//相册中选取图片操作,调用drawView中的
//调用图片需要实现UIImagePickerControllerDelegate代理
- (IBAction)loadImage:(UIBarButtonItem*)item
{
UIImagePickerController *pickerController = [[UIImagePickerController alloc]init];
pickerController.delegate = self;
pickerController.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentViewController:pickerController animated:YES completion:^{
}];
}
//照片选取后的代理方法
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
self.pickerImageContainer = [[UIView alloc]init];
self.pickerImageContainer.userInteractionEnabled = YES;
self.pickerImageContainer.frame = self.drawView.frame;
self.pickerImageView = [[UIImageView alloc] initWithImage:(UIImage*)info[@"UIImagePickerControllerOriginalImage"]];
self.pickerImageView.frame = self.drawView.bounds;
self.pickerImageView.userInteractionEnabled = YES;
//照片选取后,先创建成ImageView,通过添加拖动、捏合、旋转等手势,对照片做一些形变操作,然后通过长按操作,将图片传图绘图View中的上下文
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panAction:)];
pan.delegate = self;
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinchAction:)];
pinch.delegate = self;
UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotationAction:)];
rotation.delegate = self;
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)];
[self.pickerImageView addGestureRecognizer:pan];
[self.pickerImageView addGestureRecognizer:pinch];
[self.pickerImageView addGestureRecognizer:rotation];
[self.pickerImageView addGestureRecognizer:longPress];
[self.pickerImageContainer addSubview:self.pickerImageView];
[self.view addSubview:self.pickerImageContainer];
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)panAction:(UIPanGestureRecognizer*)pan
{
CGPoint touchPoint = [pan translationInView:self.pickerImageView];
self.pickerImageView.transform = CGAffineTransformTranslate(self.pickerImageView.transform, touchPoint.x, touchPoint.y);
[pan setTranslation:CGPointZero inView:self.pickerImageView];
}
- (void)pinchAction:(UIPinchGestureRecognizer*)pinch
{
self.pickerImageView.transform = CGAffineTransformScale(self.pickerImageView.transform, pinch.scale, pinch.scale);
[pinch setScale:1];
}
- (void)rotationAction:(UIRotationGestureRecognizer*)rotation
{
self.pickerImageView.transform = CGAffineTransformRotate(self.pickerImageView.transform, rotation.rotation);
[rotation setRotation:0];
}
//通过长按操作,将图片传图绘图View中的上下文
- (void)longPress:(UILongPressGestureRecognizer*)longPress
{
if(longPress.state == UIGestureRecognizerStateBegan)
{
[UIView animateWithDuration:0.5 animations:^{
self.pickerImageView.alpha = 0.5;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.5 animations:^{
self.pickerImageView.alpha = 1;
} completion:^(BOOL finished) {
UIGraphicsBeginImageContextWithOptions(longPress.view.bounds.size, NO, 0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.pickerImageContainer.layer renderInContext:ctx];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.drawView.pickerImage = image;
[self.pickerImageView removeFromSuperview];
self.pickerImageView = nil;
[self.pickerImageContainer removeFromSuperview];
self.pickerImageContainer = nil;
}];
}];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
@end
由于画板中创建的对象有绘制的线条以及图像,所以创建一个数据模型,保存路径信息或者图像信息
PathItem.h
#import <UIKit/UIKit.h>
@interface PathItem : NSObject
@property(assign,nonatomic)NSInteger ItemType;
@property(strong,nonatomic)UIBezierPath *path;
@property(strong,nonatomic)UIColor *color;
@property(assign,nonatomic)CGFloat lineWidth;
@property(strong,nonatomic)UIImage *image;
//创建一个线条对象
+ (instancetype)itemWithPath:(UIBezierPath*)path color:(UIColor*) color lineWidth:(CGFloat) lineWidth;
//创建一个图像对象
+ (instancetype)itemWithImage:(UIImage*)image;
@end
PathItem.m
#import "PathItem.h"
@implementation PathItem
+ (instancetype)itemWithPath:(UIBezierPath*)path color:(UIColor*) color lineWidth:(CGFloat) lineWidth
{
PathItem *item = [[PathItem alloc]init];
item.ItemType = 0;
item.path = path;
item.color = color;
item.lineWidth = lineWidth;
return item;
}
+ (instancetype)itemWithImage:(UIImage*)image
{
PathItem *item = [[PathItem alloc]init];
item.ItemType = 1;
item.image = image;
return item;
}
@end
DrawView.h
#import <UIKit/UIKit.h>
@interface DrawView : UIView
@property(strong,nonatomic)UIColor *strokeColor;
@property(assign,nonatomic)NSInteger selectedLineWidth;
//定义一些画板操作的方法,比如撤销,清屏,保存,选取图片等
- (void)undo;
- (void)clearCanvas;
- (void)saveImage;
- (void)setPickerImage:(UIImage *)pickerImage;
@end
DrawView.m
#import "DrawView.h"
#import "PathItem.h"
@interface DrawView()
@property(weak,nonatomic)UIBezierPath *path;
@property(strong,nonatomic)NSMutableArray<PathItem*> *paths;
@end
@implementation DrawView
- (void)awakeFromNib
{
[super awakeFromNib];
//添加拖动事件
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGestrue:)];
[self addGestureRecognizer:pan];
}
- (NSMutableArray<PathItem*> *)paths
{
if(_paths == nil)
{
_paths = [NSMutableArray array];
}
return _paths;
}
//拖动事件处理
- (void)panGestrue:(UIPanGestureRecognizer*) pan
{
CGPoint currentPoint = [pan locationInView:self];
if(pan.state == UIGestureRecognizerStateBegan)
{
//手指按下,创建路径
UIBezierPath *path = [UIBezierPath bezierPath];
self.path = path;
PathItem *item = [PathItem itemWithPath:path color:self.strokeColor lineWidth:self.selectedLineWidth];
//数据模型数组添加一个模型对象
[self.paths addObject:item];
[path moveToPoint:currentPoint];
}
else if(pan.state == UIGestureRecognizerStateChanged)
{
//手指移动,添加路径
[self.path addLineToPoint:currentPoint];
//重绘
[self setNeedsDisplay];
}
else if(pan.state == UIGestureRecognizerStateEnded)
{
}
}
- (void)drawRect:(CGRect)rect {
根据数据模型的数组元素区分是要绘制线条还是图像
for(PathItem *item in self.paths)
{
if(item.ItemType == 0)
{
[item.path setLineJoinStyle:kCGLineJoinRound];
[item.path setLineWidth:item.lineWidth];
[item.color setStroke];
[item.path stroke];
}
else
{
[item.image drawInRect:self.bounds];
}
}
}
//撤销操作,将模型数组最后一个添加的元素移除,然后进行重绘
- (void)undo
{
if(self.paths.count > 0)
{
[self.paths removeObjectAtIndex:self.paths.count - 1];
}
[self setNeedsDisplay];
}
//清屏操作,将模型数组所有元素移除,然后进行重绘
- (void)clearCanvas
{
[self.paths removeAllObjects];
[self setNeedsDisplay];
}
//将当前绘制到上下文中的内容以图片的方式保存倒系统相册中
- (void)saveImage
{
UIGraphicsBeginImageContext(self.bounds.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.layer renderInContext:ctx];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(newImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
//注意,UIImageWriteToSavedPhotosAlbum中的@selector只能用如下方法,不能自定义其它方法
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
//当图片保存到相册后的一些处理
}
//创建一个图像对象到画板
- (void)setPickerImage:(UIImage *)pickerImage
{
PathItem *item = [PathItem itemWithImage:pickerImage];
//添加到数据模型的数组中
[self.paths addObject:item];
[self setNeedsDisplay];
}
@end