zoukankan      html  css  js  c++  java
  • Quartz2D复习(三) --- 涂鸦

    和上一篇手势解锁不一样,手势解锁只画了一条路径,从触摸开始--》触摸移动--》触摸结束 ,然后路径完成了,渲染出来就是手势解锁了;

    这次涂鸦想做到的效果是可以画很多次线段或弧,每次又可以设置不同的宽度和颜色,然后还要有撤销、清屏、橡皮擦的功能,那就需要画很多条路径了,然后每条路径有自己的颜色和宽度,那么

    UIBezierPath类也实现不了,需要自定义一个类,继承自UIBezierPath,然后再增加自己的颜色和宽度属性。

    效果截图:

      涂鸦了   橡皮擦擦除  

    保存到相册

     

    代码:

    1、自定义PaintingBezierPath类继承自UIBezierPath类,增加一个自定义路径颜色的属性;自定义构造函数,设置颜色和路径宽度

    PaintingBezierPath.h文件代码:

    #import <UIKit/UIKit.h>
    
    @interface PaintingBezierPath : UIBezierPath
    
    @property (nonatomic, retain) UIColor *color; //线段的颜色
    
    - (instancetype)initWithColor: (UIColor *)color WithWidth: (CGFloat)width WithStartPoint: (CGPoint)startPoint;
    
    @end
    

    PaintingBezierPath.m文件代码:

     1 //
     2 //  PaintingBezierPath.m
     3 //  tan_iosTwo
     4 //
     5 //  Created by xiaom on 15/7/22.
     6 //
     7 //  为了自定义每个轨迹的宽度和颜色,需要增加一个自定义方法
     8 
     9 #import "PaintingBezierPath.h"
    10 
    11 @implementation PaintingBezierPath
    12 
    13 - (instancetype)initWithColor:(UIColor *)color WithWidth:(CGFloat)width WithStartPoint:(CGPoint)startPoint{
    14     if (self = [super init]){
    15         self.color = color;
    16         self.lineWidth = width;
    17         self.lineJoinStyle = kCGLineJoinRound;
    18         self.lineCapStyle = kCGLineCapRound;
    19         [self moveToPoint:startPoint];
    20     }
    21     return self;
    22 }
    23 
    24 @end
    View Code

    2、自定义view, 用来展示涂鸦,名称为:PaintingView

    PaintingView.h文件代码:

    #import <UIKit/UIKit.h>
    
    @interface PaintingView : UIView
    
    @property (nonatomic, assign) CGFloat lineWidth; //涂鸦的线段宽度
    @property (nonatomic, strong) UIColor *lineColor; //涂鸦的线段颜色
    
    - (void)cancelPainting; //撤销涂鸦
    - (void)clearScreen; //清屏
    - (void)saveImgToAlbum; //保存相片到到手机相册里
    
    @end
    

    PaintingView.m文件代码:

      1 //  绘画, 涂鸦
      2 
      3 #import "PaintingView.h"
      4 #import "PaintingBezierPath.h"
      5 
      6 @interface PaintingView()
      7 
      8 @property (nonatomic, retain) NSMutableArray *paths; //涂鸦路径数组
      9 @property (nonatomic, retain) PaintingBezierPath *currentPath; //当前正在绘制的path
     10 
     11 @end
     12 
     13 @implementation PaintingView
     14 
     15 //代码创建对象会调用: 使用
     16 - (instancetype)initWithFrame:(CGRect)frame{
     17     if (self = [super initWithFrame:frame]){
     18         //NSLog(@"frame...%s", __func__);
     19     }
     20     return self;
     21 }
     22 
     23 //xib创建会调用
     24 - (instancetype)initWithCoder:(NSCoder *)aDecoder{
     25     if (self = [super initWithCoder:aDecoder]){
     26         //NSLog(@"coder.. %s", __func__);
     27     }
     28     return self;
     29 }
     30 
     31 //监听触摸开始 ,方法继承自UIResponder
     32 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
     33     PaintingBezierPath *path = [[PaintingBezierPath alloc] initWithColor:self.lineColor WithWidth:self.lineWidth WithStartPoint:[self currentPoint:touches]];
     34     
     35     [self.paths addObject:path]; //将路径记录到数组中
     36     self.currentPath = path;
     37     
     38     [self setNeedsDisplay];  //调用方法,重新绘制
     39 }
     40 
     41 //监听触摸移动中
     42 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
     43     //追踪每次路径的移动过程
     44     [self.currentPath addLineToPoint:[self currentPoint:touches]];
     45     
     46     [self setNeedsDisplay]; //调用方法,重新绘制
     47 }
     48 
     49 //获取view对象中的当前位置
     50 - (CGPoint)currentPoint: (NSSet *)touches{
     51     UITouch *touch = [touches anyObject];
     52     return [touch locationInView:self];
     53 }
     54 
     55 //次方法是UIView的分类@interface UIView(UIViewRendering)中添加的方法
     56 //setNeedsDisplay方法也是此分类中的方法
     57 - (void)drawRect:(CGRect)rect{
     58     for (int i = 0; i < self.paths.count; i++) {
     59         PaintingBezierPath *path = [self.paths objectAtIndex:i];
     60         [path.color set];
     61         [path stroke];  //渲染
     62     }
     63 }
     64 
     65 #pragma mark - 自定义方法实现
     66 //撤销
     67 - (void)cancelPainting{
     68     [self.paths removeLastObject]; //移除最后一个路径对象
     69     [self setNeedsDisplay]; //重新绘制
     70 }
     71 
     72 //清屏
     73 - (void)clearScreen{
     74     [self.paths removeAllObjects]; //移除所有路径
     75     self.lineColor = nil; //颜色赋空
     76     [self setNeedsDisplay]; //重新绘制
     77 }
     78 
     79 //保存图片到相册
     80 - (void)saveImgToAlbum{
     81     //1、开启图形上下文
     82     UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
     83     //2、获取当前上下文
     84     CGContextRef ctr = UIGraphicsGetCurrentContext();
     85     //3、渲染当前View的图层到上下文中
     86     [self.layer renderInContext:ctr];
     87     //4、获取新图片
     88     UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
     89     //5、关闭图形上下文
     90     UIGraphicsEndImageContext();
     91     //6、保存图片到相册中
     92     UIImageWriteToSavedPhotosAlbum(newImg, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
     93 }
     94 
     95 //保存图片到相册完成之后的处理
     96 - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
     97     UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(60, 150, 200, 100)];
     98     [lbl setBackgroundColor:[UIColor blackColor]];
     99     lbl.textAlignment = NSTextAlignmentCenter;
    100     lbl.textColor = [UIColor yellowColor];
    101     
    102     if (error){ //保存失败
    103         lbl.text = @"保存失败";
    104     }
    105     else{ //保存成功
    106         lbl.text = @"保存成功";
    107     }
    108     [self addSubview:lbl];
    109     
    110     [UIView animateWithDuration:2.0 animations:^{
    111         lbl.alpha = 0.1;
    112     } completion:^(BOOL finished) {
    113         [lbl removeFromSuperview];
    114     }];
    115 }
    116 
    117 //设置对象默认属性值
    118 - (CGFloat)lineWidth{
    119     if (_lineWidth < 1){
    120         _lineWidth = 1;
    121     }
    122     return _lineWidth;
    123 }
    124 
    125 - (UIColor *)lineColor{
    126     if (_lineColor == nil){
    127         _lineColor = [UIColor blackColor];
    128     }
    129     return _lineColor;
    130 }
    131 
    132 - (NSMutableArray *)paths{
    133     if (_paths == nil){
    134         _paths = [[NSMutableArray alloc] init];
    135     }
    136     return _paths;
    137 }
    138 
    139 /*
    140 // Only override drawRect: if you perform custom drawing.
    141 // An empty implementation adversely affects performance during animation.
    142 - (void)drawRect:(CGRect)rect {
    143     // Drawing code
    144 }
    145 */
    146 
    147 @end
    View Code

    3、自定义控制器展示PaintingView

    DoodleViewController.h文件:

    #import <UIKit/UIKit.h>
    
    @interface DoodleViewController : UIViewController
    
    @end
    

    DoodleViewController.m

      1 //  信手涂鸦
      2 
      3 #import "DoodleViewController.h"
      4 #import "PaintingView.h"
      5 
      6 @interface DoodleViewController ()
      7 
      8 @property (nonatomic, retain) PaintingView *paintV; //涂鸦的画板
      9 
     10 @end
     11 
     12 @implementation DoodleViewController
     13 
     14 - (void)viewDidLoad {
     15     [super viewDidLoad];
     16     // Do any additional setup after loading the view.
     17     [self.view setBackgroundColor:[UIColor whiteColor]];
     18     
     19     //自定义View涂鸦
     20     PaintingView *v = [[PaintingView alloc] initWithFrame:CGRectMake(0, 80, 320, 450)];
     21     [v setBackgroundColor:[UIColor grayColor]];
     22     [v setAlpha:0.6];
     23     [self.view addSubview:v];
     24     self.paintV = v;
     25     
     26     [self addReturnBtn];    //添加返回按钮
     27     [self addDoodleSetWidthAndColor]; //增加设置涂鸦的宽度和颜色设置
     28 }
     29 
     30 //添加返回按钮
     31 - (void)addReturnBtn{
     32     UIButton *returnBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 20, 50, 30)];
     33     [returnBtn setTitle:@"返回" forState:UIControlStateNormal];
     34     [returnBtn addTarget:self action:@selector(returnPrePage) forControlEvents:UIControlEventTouchUpInside];
     35     [returnBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
     36     [self.view addSubview:returnBtn];
     37 }
     38 
     39 //添加涂鸦宽度设置和颜色设置
     40 - (void)addDoodleSetWidthAndColor{
     41     //1、增加UISlider用来设置可调节宽度
     42     UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(50, 20, 80, 30)];
     43     slider.maximumValue = 15.0f; //最大值
     44     slider.value = 3.0f;    //默认为1
     45     self.paintV.lineWidth = slider.value;
     46     [slider addTarget:self action:@selector(setLineWidth:) forControlEvents:UIControlEventValueChanged]; //绑定值改变事件
     47     [self.view addSubview:slider];
     48     
     49     //2、添加颜色选择按钮
     50     NSArray *colors = @[[UIColor redColor], [UIColor yellowColor], [UIColor greenColor], [UIColor blueColor], [UIColor purpleColor], [UIColor brownColor]];
     51     for (int i = 0; i < colors.count; i++) {
     52         CGFloat x =  140 + 30 * i;
     53         UIButton *colorBtn = [[UIButton alloc] initWithFrame:CGRectMake(x, 25, 20, 20)];
     54         [colorBtn setBackgroundColor:[colors objectAtIndex:i]];
     55         [colorBtn addTarget:self action:@selector(setLineColor:) forControlEvents:UIControlEventTouchUpInside];
     56         [self.view addSubview:colorBtn];
     57     }
     58     
     59    
     60     //第二行
     61     //3、添加撤销按钮
     62     UIButton *cancelBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 55, 60, 25)];
     63     [cancelBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
     64     [cancelBtn setTitle:@"撤销" forState:UIControlStateNormal];
     65     [cancelBtn addTarget:self action:@selector(cancelPainting) forControlEvents:UIControlEventTouchUpInside];
     66     [self.view addSubview:cancelBtn];
     67     
     68     //4、清屏按钮
     69     UIButton *clearScreenBtn = [[UIButton alloc] initWithFrame:CGRectMake(70, 55, 60, 25)];
     70     [clearScreenBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
     71     [clearScreenBtn setTitle:@"清屏" forState:UIControlStateNormal];
     72     [clearScreenBtn addTarget:self action:@selector(clearScreen) forControlEvents:UIControlEventTouchUpInside];
     73     [self.view addSubview:clearScreenBtn];
     74     
     75     //5、添加一个橡皮擦
     76     UIButton *brushBtn = [[UIButton alloc] initWithFrame:CGRectMake(140, 55, 60, 25)];
     77     [brushBtn setTitle:@"橡皮擦" forState:UIControlStateNormal];
     78     [brushBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
     79     [brushBtn addTarget:self action:@selector(brush) forControlEvents:UIControlEventTouchUpInside];
     80     [self.view addSubview:brushBtn];
     81     
     82     //6、保存到相册按钮
     83     UIButton *saveBtn = [[UIButton alloc] initWithFrame:CGRectMake(210, 55, 100, 25)];
     84     [saveBtn setTitle:@"保存到相册" forState:UIControlStateNormal];
     85     [saveBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
     86     [saveBtn addTarget:self action:@selector(saveImgToAlbum) forControlEvents:UIControlEventTouchUpInside];
     87     [self.view addSubview:saveBtn];
     88 }
     89 
     90 //调节宽度
     91 - (void)setLineWidth:(UISlider *)sender{
     92     [self.paintV setLineWidth:sender.value];
     93 }
     94 
     95 //调节颜色
     96 - (void)setLineColor: (UIButton *)sender{
     97     [self.paintV setLineColor:sender.backgroundColor];
     98 }
     99 
    100 //设置橡皮擦
    101 - (void)brush{
    102     self.paintV.lineColor = self.paintV.backgroundColor;
    103     if (self.paintV.lineWidth < 5) self.paintV.lineWidth = 5;
    104 }
    105 //撤销
    106 - (void)cancelPainting{
    107     [self.paintV cancelPainting];
    108 }
    109 //清屏
    110 - (void)clearScreen{
    111     [self.paintV clearScreen];
    112 }
    113 
    114 //保存图片到相册
    115 - (void)saveImgToAlbum{
    116     [self.paintV saveImgToAlbum];
    117 }
    118 
    119 //返回上一页
    120 - (void)returnPrePage{
    121     [self dismissViewControllerAnimated:YES completion:nil];
    122 }
    123 
    124 - (void)didReceiveMemoryWarning {
    125     [super didReceiveMemoryWarning];
    126     // Dispose of any resources that can be recreated.
    127 }
    128 
    129 /*
    130 #pragma mark - Navigation
    131 
    132 // In a storyboard-based application, you will often want to do a little preparation before navigation
    133 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    134     // Get the new view controller using [segue destinationViewController].
    135     // Pass the selected object to the new view controller.
    136 }
    137 */
    138 
    139 @end
    View Code

     

  • 相关阅读:
    CRL线程池调度和配置的一些细节
    迁移到iis7
    musicstore edit方法出错的原因和解决方法
    如何分离出EF的三份结构定义文件
    在GridView中 鼠标移动到行 该行颜色变换
    飘逸程序员的老家
    [转贴]ASP.NET中常用的26个优化性能方案
    【转贴】在ASP.NET中显示进度条ASP.NET
    在使用GridView中删除的按钮弹出提示框最简单的一中方法
    【转贴】ASP.NET图表控件
  • 原文地址:https://www.cnblogs.com/tandaxia/p/4672175.html
Copyright © 2011-2022 走看看