iOS之QuartZ 2D 绘图(一)

96
追逐iOS
0.1 2019.05.21 16:19* 字数 545

Quartz2D

  • Quartz2D是苹果封装的一个库,针对iOS和os系统绘制不同的类型的制图方式

  • 图形上下文(一种数据类型,类似int,double)数据类型(CGContextRef)

  • 不同的上下文(数据类型)可以绘制不同的类型(pdf,bitmap,layer,window,ptinter)

  • 进而上面5中类型,对应不同的上下文

1. 绘制简单图形 -> 画线

  • 在自定义的View我们可以通知drawRect:方法绘制,自己想要的线条
  • 苹果内部已经创建了一个layerView上下文关联
01_line.png
/控制器View将要显示的时候调用
//-(void)viewWillAppear:(BOOL)animated 方法之后调用
- (void)drawRect:(CGRect)rect {
    
    //1.获取上下文
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    //2.创建线
    UIBezierPath *path = [UIBezierPath bezierPath];
    //设置起点
    [path moveToPoint:CGPointMake(50, 200)];
    
    //终点
    [path addLineToPoint:CGPointMake(300, 30)];
    
    //如果在添加线的时候 默认是从终点当做另一条线的起点
    [path addLineToPoint:CGPointMake(300, 250)];
    
    //设置颜色
    [[UIColor blackColor] set];
    //设置线宽
    CGContextSetLineWidth(contextRef, 5.0f);
    //设置链接点的 角度 枚举值
    /*
     kCGLineJoinMiter,
     kCGLineJoinRound,
     kCGLineJoinBevel
     */
    CGContextSetLineJoin(contextRef, kCGLineJoinRound);
    
    //CGContextSetBlendMode(contextRef, kCGBlendModeScreen);
    
    //3.绘制
    //UIBezierPath 是UIKit矿建,需要转化
    CGContextAddPath(contextRef, path.CGPath);
    
    //4.渲染到View上
    CGContextStrokePath(contextRef);
    
}


2.贝塞尔曲线UIBezierPath

  • 苹果封装的一个可快速创建绘制图形的类
  • 其内部也是要实现:
    • 1.获取上下文
    • 2.描述路径
    • 3.把路径添加到上下文
    • 4.渲染上下文
- (void)drawRect:(CGRect)rect {
    
    //创建路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    //设置起点
    
    [path moveToPoint:CGPointMake(50, 50)];
    
    //设置终点
    
    [path addLineToPoint:CGPointMake(300, 300)];
    
    //绘制 描边
    [path stroke];
    //1.获取上下文
    //2.描述路径
    //3.把路径添加到上下文
    //4.渲染上下文
    
    
}

2.1UIBezierPath常用的类方法

2.1.1 bezierPathWithRect: 绘制简单的图形:矩形,长方形

- (void)drawRect:(CGRect)rect {
    
    //创建路径
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 200, 200)];
    //描边
    [path stroke];
    
    
}
03_rect.png

2.1.2bezierPathWithRoundedRect: cornerRadius:

参数一:要绘制的图形点 参数二:是圆角半径,当圆角半径等于一半就是圆(宽度和高度相等的情况下)

- (void)drawRect:(CGRect)rect {
    
    //创建路径
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 200, 100) cornerRadius:50];
    path.lineWidth = 10.f;
    
    [path stroke];
    
    
}
04_椭圆.png

2.1.3 绘制圆弧

+ (instancetype)bezierPathWithArcCenter:(CGPoint)center
radius:(CGFloat)radius 
startAngle:(CGFloat)startAngle 
endAngle:(CGFloat)endAngle 
clockwise:(BOOL)clockwise
参数一: 圆心
参数二: 半径
参数三: 开始的角度
参数四: 结束的角度
参数五; 绘制的方向 (顺时针还是逆时针)

   //创建路径
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:self.center radius:50 startAngle:M_PI endAngle:0 clockwise:YES];
    path.lineWidth = 10.f;
    [[UIColor redColor] set];
    [path stroke];
    // 起点是0 
    //顺时针正
    //逆时针负

05_圆弧.png
2.1.4 UIBezierPath二阶曲线

参数一:终点
参数二: 控制点
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;

- (void)drawRect:(CGRect)rect {
    
  //创建路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    //设置起点
    [path moveToPoint:CGPointMake(50, 200)];
    //设置终点和控制点
    [path addQuadCurveToPoint:CGPointMake(200, 50) controlPoint:CGPointMake(20, 20)];
    //设置颜色
    [[UIColor redColor] set];
    //描边
    [path stroke];
    
}

WX20190514-141555.png
2.1.5UIBezierPath三阶曲线
- (void)drawRect:(CGRect)rect {
    
    UIBezierPath *path = [UIBezierPath bezierPath];
    
    [path moveToPoint:CGPointMake(50, 200)];

    [path addCurveToPoint:CGPointMake(270, 80) controlPoint1:CGPointMake(50, 80) controlPoint2:CGPointMake(200, 200)];
    
    [[UIColor redColor] set];
    
    [path stroke];
    

    
}
WX20190514-142254.png

下载进度的绘制 小demo

  • 可用于 图片的展示(下载进度)
110.gif

#import "CCDownloadProgressView.h"


@interface CCDownloadProgressView ()

@property (nonatomic, weak) UILabel *progressLabel;


@end


@implementation CCDownloadProgressView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        
    }
    
    return self;
}


- (void)awakeFromNib{
    [super awakeFromNib];
    
}

//界面显示的时候调用
//核心代码
- (void)drawRect:(CGRect)rect {
    
    //获取上下文
//    CGContextRef ref = UIGraphicsGetCurrentContext();
    
    //绘制路径
    CGFloat width = rect.size.width *0.5;
    CGFloat height = rect.size.height *0.5;
    CGPoint center = CGPointMake(width, height);
    CGFloat endAng = 2 *M_PI *self.progress + (-M_PI_2);
    
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:width - 10 startAngle:-M_PI_2 endAngle:endAng clockwise:YES];
    //设置颜色
    [self.circleColor set];
    //把路径
    [path stroke];
    
}


- (void)setProgress:(CGFloat)progress {
    _progress = progress;
    
    self.progressLabel.text = [NSString stringWithFormat:@"%.1f%%",progress *100];
    //重新绘制
    [self setNeedsDisplay];
}

- (void)setCircleColor:(UIColor *)circleColor{
    _circleColor = circleColor;
    self.progressLabel.textColor = circleColor;
}


- (void)layoutSubviews {
    [super layoutSubviews];
    
    self.progressLabel.frame = self.bounds;
}


- (UILabel *)progressLabel {
    if (!_progressLabel) {
        
        UILabel *contenLabel = [[UILabel alloc] init];
        contenLabel.textAlignment = NSTextAlignmentCenter;
        [self addSubview:contenLabel];
        self.progressLabel = contenLabel;
        
    }
    
    return _progressLabel;
}

@end


3. 绘制文字

方法一

- (void)drawAtPoint:(CGPoint)point withAttributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attrs
缺点:
这个方法 绘制出来的文字不能换行

//绘制文字
- (void)drawRect:(CGRect)rect {
    
    NSString *text = @"这是一个文字的g绘制效果";
    
    //设置 字体的属性
    NSDictionary *att = @{
                          NSFontAttributeName:[UIFont systemFontOfSize:20],
                          NSForegroundColorAttributeName:[UIColor redColor]
                          
                          };
    
    [text drawAtPoint:CGPointZero withAttributes:att];
   
  
}


WX20190521-165012.png
方法二
//绘制文字
- (void)drawRect:(CGRect)rect {
    
    NSString *text = @"这是一个文字的g绘制效果,这是一个文字的g绘制效果,这是一个文字的g绘制效果,这是一个文字的g绘制效果,这是一个文字的g绘制效果,这是一个文字的g绘制效果";
    
    NSDictionary *att = @{
                          NSFontAttributeName:[UIFont systemFontOfSize:20],
                          NSForegroundColorAttributeName:[UIColor redColor]
                          
                          };
    [text drawInRect:CGRectMake(0, 0, 300, 300) withAttributes:att];
   
    
}


WX20190521-170925.png
方法三

- (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attributes context:(nullable NSStringDrawingContext *)context
这个方法,可以根据字体的多少,来计算高度
类似我们经常使用 计算 文本高度的方法

- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attributes context:(nullable NSStringDrawingContext *)context


//绘制文字
- (void)drawRect:(CGRect)rect {
    
    NSString *text = @"5月20日,习近平赴江西考察调研。上午,他到了位于赣州市区的江西金力永磁科技股份有限公司,下午的行程则集中在了赣州于都县。一周之前的中共中央政治局会议决定,从今年6月开始,在全党自上而下分两批开展“不忘初心、牢记使命”主题教育。在主题教育即将开展之际,习近平总书记此次到访中央红军长征集结出发地,引人关注";
    
    NSDictionary *att = @{
                          NSFontAttributeName:[UIFont systemFontOfSize:20],
                          NSForegroundColorAttributeName:[UIColor redColor]
                          
                          };
    
    
    //设置宽度是300, 告诉是 无线大
    CGSize textSize = CGSizeMake(300, MAXFLOAT);
    
    [text drawWithRect:CGRectMake(0, 0, textSize.width, textSize.height) options:NSStringDrawingUsesLineFragmentOrigin attributes:att context:nil];
   
    
}



WX20190521-173523.png

补充:计算文本高度的方法

方式一
  • boundingRectWithSize:options:attributes:方法,适用于换行的情况,也适用于不换行的情况,为了兼容两者的方法
   //文本内容
       CGSize chatContentSize = [self sizeWithText:text WithMaxSize:CGSizeMake(cellMaxw, MAXFLOAT) fontSize:contentTextFont];
//计算字体宽高

- (CGSize)sizeWithText:(NSString *)text WithMaxSize:(CGSize)maxSize fontSize:(CGFloat)fontSize
{
    
    return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]} context:nil].size;
}

方式二
  • sizeWithAttributes:计算文本宽度和高度,不会自动换行

    NSString *text = @"5月20日,习近平赴江西考察调研。上午,他到了位于赣州市区的江西金力永磁科技股份有限公司,下午的行程则集中在了赣州于都县。一周之前的中共中央政治局会议决定,从今年6月开始,在全党自上而下分两批开展“不忘初心、牢记使命”主题教育。在主题教育即将开展之际,习近平总书记此次到访中央红军长征集结出发地,引人关注";
    
    NSDictionary *att = @{
                          NSFontAttributeName:[UIFont systemFontOfSize:20],
                          NSForegroundColorAttributeName:[UIColor redColor]
                          
                          };
    
  
    CGSize textSize = [text sizeWithAttributes:att];
    //打印高度
   NSLog(@"%@",NSStringFromCGSize(textSize));

iOS基础