简单画板实例

制作一个简单的画板,可以绘图,可以从相册添加照片,最后可以保存到相册

界面布局如图

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

results matching ""

    No results matching ""