UI高级 一一 画板

来源:互联网 发布:淘宝药店可靠吗 编辑:程序博客网 时间:2024/04/30 05:05


本文源代码请参考: https://github.com/coderZYGui/drawingBoard


利用Quartz2D 实现画板功能,效果如下图



功能实现步骤:

1.界面搭建(使用autolayout自动布局),顶部使用Toorbar来管理多个item

中间画板是一个View,底部一个View上放一个UISlider和三个Button,并做布局操作.

2. 实现画线: 每条线都是新的path,所以把每个path都保存在数组中,画线的时候从数组中取出.

3. 设置属性功能: 设置清屏,撤销,UISlider等相关业务逻辑.因为清屏,撤销,橡皮擦,线宽,线色属于画板的功能

因此写在画板类中.

4. 绘制图片到画板: 从系统相册中选择图片后,对图片做拖动,旋转,平移等形变操作. 长按图片时,将图片绘制到画板中.

注意: 这里采用的方式是: 对一个UIView进行截屏操作,在UIView中放置一个UIImageView,将相册的image保存到UIImageView的image中.然后利用UIView的代理属性将图片传给画板的image.


代码如下:

ViewController文件

////  ViewController.m//  DrawingBoard////  Created by 朝阳 on 2017/10/14.//  Copyright © 2017年 sunny. All rights reserved.//#import "ViewController.h"#import "ZYDrawView.h"#import "ZYHandleImageView.h"@interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate,ZYHandleImageViewDelegate>@property (weak, nonatomic) IBOutlet ZYDrawView *drawView;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    }// 操作属于谁,写在谁的类中/** 清屏 */- (IBAction)clear:(UIBarButtonItem *)sender {    [self.drawView clear];}/** 撤销 */- (IBAction)undo:(UIBarButtonItem *)sender {    [self.drawView undo];}/** 橡皮擦 */- (IBAction)eraser:(UIBarButtonItem *)sender {    [self.drawView eraser];}/** 设置线宽 */- (IBAction)setLineWidth:(UISlider *)slider {    [self.drawView setLineWidth:slider.value];}/** 设置线颜色 */- (IBAction)setLineColor:(UIButton *)button {    [self.drawView setLineColor:button.backgroundColor];}/** 照片 */- (IBAction)photo:(UIBarButtonItem *)sender {        //从系统相册中选择一张图片    //1. 弹出系统相册    UIImagePickerController *pickerVC = [[UIImagePickerController alloc] init];    //2. 弹出相册的类型    pickerVC.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;    //3. 设置pickerVC代理    pickerVC.delegate = self;    //3. modal出系统相册    [self presentViewController:pickerVC animated:YES completion:nil];}#pragma -mark UIImagePickerControllerDelegate/** 当选中系统相册中的图片时会调用 @param picker 系统相册控制器 @param info 存放图片的字典 */- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{    NSLog(@"%@",info);    // 系统相册是一个字典,根据key值来取出图片    UIImage *image = info[UIImagePickerControllerOriginalImage];        ZYHandleImageView *handleV = [[ZYHandleImageView alloc] initWithFrame:self.drawView.frame];    handleV.backgroundColor = [UIColor clearColor];    handleV.image = image;    // 设置代理属性    handleV.delegate = self;        [self.view addSubview:handleV];            // 系统相册modal消失    [self dismissViewControllerAnimated:YES completion:nil];}#pragma -mark ZYHandleImageViewDelegate- (void)handleImageView:(ZYHandleImageView *)handleImageView newImage:(UIImage *)newImage{    self.drawView.image = newImage;}/** 保存 */- (IBAction)save:(UIBarButtonItem *)sender {        //1. 开启一个位图上下文    UIGraphicsBeginImageContextWithOptions(self.drawView.bounds.size, NO, 0);    //2. 把drawView上的内容渲染到上下文中    CGContextRef ctx = UIGraphicsGetCurrentContext();    [self.drawView.layer renderInContext:ctx];    //3. 从上下文中生成新的图片    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();        //把图片保存到桌面//    NSData *data = UIImagePNGRepresentation(newImage);//    [data writeToFile:@"/Users/sunny/Desktop/photo.png" atomically:YES];        //4. 把图片保存到系统相册中    // 注意: 弹出系统相册必须实现 image:didFinishSavingWithError:contextInfo:方法    UIImageWriteToSavedPhotosAlbum(newImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);}- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{    NSLog(@"saveSuccess");}/** 隐藏导航 */- (BOOL)prefersStatusBarHidden{    return YES;}@end

ZYDrawView文件(画板)

////  ZYDrawView.h//  DrawingBoard////  Created by 朝阳 on 2017/10/14.//  Copyright © 2017年 sunny. All rights reserved.//#import <UIKit/UIKit.h>@interface ZYDrawView : UIView@property (nonatomic, strong) UIImage *image;// 清屏- (void)clear;// 撤销- (void)undo;// 擦除- (void)eraser;// 设置线宽- (void)setLineWidth:(CGFloat)width;// 设置线的颜色- (void)setLineColor:(UIColor *)color;@end#import "ZYDrawView.h"#import "ZYBezierPath.h"/** 定义类扩展 */@interface ZYDrawView ()@property (nonatomic, strong) UIBezierPath *path;/** 用来保存所有的path */@property (nonatomic, strong) NSMutableArray *allPaths;/** 线宽 */@property (nonatomic, assign) CGFloat width;/** 线色 */@property (nonatomic, strong) UIColor *color;@end@implementation ZYDrawView- (NSMutableArray *)allPaths{    if (!_allPaths) {        self.allPaths = [NSMutableArray array];    }    return _allPaths;}- (void)awakeFromNib{    [super awakeFromNib];    // 添加手势    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];    [self addGestureRecognizer:pan];                // 设置一个默认线宽和线色    self.width = 1;    self.color = [UIColor blackColor];    }// 清屏- (void)clear{    [self.allPaths removeAllObjects];    // 重绘    [self setNeedsDisplay];}// 撤销- (void)undo{    [self.allPaths removeLastObject];    [self setNeedsDisplay];}// 擦除- (void)eraser{    [self setLineColor:[UIColor whiteColor]];}// 设置线宽- (void)setLineWidth:(CGFloat)width{    self.width = width;    }// 设置线的颜色- (void)setLineColor:(UIColor *)color{    self.color = color;}/** 拖动手势方法 */- (void)pan:(UIPanGestureRecognizer *)pan{    // 获取当前手指所在的点    CGPoint curP = [pan locationInView:self];    // 判断手势状态    if (pan.state == UIGestureRecognizerStateBegan) {        // 创建路径        ZYBezierPath *path = [[ZYBezierPath alloc] init];        self.path = path;                // 设置线宽        [path setLineWidth:self.width];        path.color = self.color;                // 设置起点        [path moveToPoint:curP];        // 把路径保存到数组中        [self.allPaths addObject:self.path];            }else if(pan.state == UIGestureRecognizerStateChanged){        [self.path addLineToPoint:curP];        // 重绘,调用drawRect方法        [self setNeedsDisplay];    }}- (void)setImage:(UIImage *)image{    _image = image;    // 把图片添加到数组中    [self.allPaths addObject:image];    // 重绘    [self setNeedsDisplay];}- (void)drawRect:(CGRect)rect {        for (ZYBezierPath *path in self.allPaths) {        // 判断path的真实类型        if ([path isKindOfClass:[UIImage class]]) {            UIImage *image = (UIImage *)path;            // 把图片绘制到画板中(填充整个区域)            [image drawInRect:rect];        }else{            [path.color set];            [path stroke];        }    }    }@end

ZYBezierPath文件(继承自UIBezierPath,系统UIBezierPath功能不够用)

////  ZYBezierPath.h//  DrawingBoard////  Created by 朝阳 on 2017/10/14.//  Copyright © 2017年 sunny. All rights reserved.//#import <UIKit/UIKit.h>@interface ZYBezierPath : UIBezierPath@property (nonatomic,strong) UIColor *color;@end#import "ZYBezierPath.h"@implementation ZYBezierPath@end

ZYHandleImageView文件(分析中的UIView文件,继承UIView)

////  ZYHandleImageView.h//  DrawingBoard////  Created by 朝阳 on 2017/10/14.//  Copyright © 2017年 sunny. All rights reserved.//#import <UIKit/UIKit.h>@class ZYHandleImageView;@protocol ZYHandleImageViewDelegate <NSObject>- (void)handleImageView:(ZYHandleImageView *)handleImageView newImage:(UIImage *)newImage;@end@interface ZYHandleImageView : UIView@property (nonatomic, strong) UIImage *image;/** 代理属性 */@property (nonatomic, weak) id<ZYHandleImageViewDelegate> delegate;@end#import "ZYHandleImageView.h"/** 定义类扩展 */@interface ZYHandleImageView ()<UIGestureRecognizerDelegate>@property (nonatomic, strong) UIImageView *imageV;@end@implementation ZYHandleImageView- (UIImageView *)imageV{    if (!_imageV) {        UIImageView *imageV = [[UIImageView alloc] initWithFrame:self.bounds];        imageV.userInteractionEnabled = YES;        [self addSubview:imageV];        _imageV = imageV;        // 添加手势        [self addGestures];    }    return _imageV;}- (void)setImage:(UIImage *)image{    _image = image;    self.imageV.image = image;}- (void)addGestures{    // 拖拽手势    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]                                   initWithTarget:self action:@selector(pan:)];        [self.imageV addGestureRecognizer:pan];        // 捏合    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];        pinch.delegate = self;    [self.imageV addGestureRecognizer:pinch];            // 添加旋转    UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];    rotation.delegate = self;        [self.imageV addGestureRecognizer:rotation];        // 长按    UILongPressGestureRecognizer *longP = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];    [self.imageV addGestureRecognizer:longP];}// 拖动的时候调用- (void)pan:(UIPanGestureRecognizer *)pan{    // 手指移动后,相对于坐标中的偏移量    // 此时的pan.view 就相当于 UIImageView    CGPoint transP = [pan translationInView:pan.view];    pan.view.transform = CGAffineTransformTranslate(pan.view.transform, transP.x, transP.y);    // 复位    [pan setTranslation:CGPointZero inView:pan.view];    }// 捏合的时候调用- (void)pinch:(UIPinchGestureRecognizer *)pinch{    pinch.view.transform = CGAffineTransformScale(pinch.view.transform, pinch.scale, pinch.scale);    //复位    [pinch setScale:1];}// 旋转的时候调用- (void)rotation:(UIRotationGestureRecognizer *)rotation{    rotation.view.transform = CGAffineTransformRotate(rotation.view.transform, rotation.rotation);    //复位    [rotation setRotation:0];}// 长按的时候调用-(void)longPress:(UILongPressGestureRecognizer *)longPress{    // 长按时,图片闪烁一下    if (longPress.state == UIGestureRecognizerStateBegan) {                [UIView animateWithDuration:0.3 animations:^{            self.imageV.alpha = 0;                    }completion:^(BOOL finished) {            [UIView animateWithDuration:0.3 animations:^{                self.imageV.alpha = 1;                            }completion:^(BOOL finished) {                // 把相册中的图片绘制到DrawView上                //1. 开启一个位图上下文                UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);                //2. 把imageV上的内容绘制到上下文中                CGContextRef ctx = UIGraphicsGetCurrentContext();                [self.layer renderInContext:ctx];                //3. 从上下文中生成新的图片                UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();                                //4. 关闭上下文                UIGraphicsEndImageContext();                                // 若要把newImage绘制到DrawView上,需要使用代理进行传值                if ([self.delegate respondsToSelector:@selector(handleImageView:newImage:)]) {                    [self.delegate handleImageView:self newImage:newImage];                }                                //从父控件当中移除                [self removeFromSuperview];                            }];        }];    }}//能够同时支持多个手势-(BOOL)gestureRecognizer:(nonnull UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(nonnull UIGestureRecognizer *)otherGestureRecognizer{        return YES;}@end


原创粉丝点击