OCiOS开发:绘图与曲线

简介

  • iOS上,所有的绘制,无论是否采用OpenGL、Quartz、UIKit、或者 Core Animation—都发生在UIView对象的区域内,即子类化UIView,在drawRect方法中进行绘制。

  • 视图定义绘制发生的屏幕区域。如果使用系统提供的视图,绘制工作会自动得到处理。然而,如果定义自己的定制视图,则必须自行提供绘制代码。

Core Graphics 绘图

常用绘图函数

// 1、绘制椭圆
CGContextAddEllipseInRect(CGContextRef context, CGRect rect)

// 2、绘制虚线
CGContextSetLineDash(CGContextRef c, CGFloat phase,
  const CGFloat lengths[], size_t count)

// 3、绘制圆弧
CGContextAddArcToPoint(CGContextRef c, CGFloat x1, CGFloat y1,
  CGFloat x2, CGFloat y2, CGFloat radius)

CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y,
  CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)

// 4、绘制曲线
CGContextAddCurveToPoint(CGContextRef c, CGFloat cp1x,
  CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y)

// 5、绘制直线
 CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y)

// 6、绘制曲线
CGContextAddRect(CGContextRef __nullable c, CGRect rect)

填充

1、为图形填充颜色的几个函数:

// 1、填充矩形
CGContextFillRect(context, rectangl);

// 2、填充椭圆或圆
CGContextFillEllipseInRect(context, rectangle);

// 3、填充路径
CGContextFillPath(context); 

注意:在填充颜色之前首先要调用 CGContextSetFillColorWithColor() 定制填充颜色。

2、代码示例:

- (void)drawRect:(CGRect)rect {

    // 获取上下文(画布)
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 设置线条宽度
    CGContextSetLineWidth(context, 3.0);
    // 设置线条颜色
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);

    // 创建一个椭圆,如果 width = height 则是一个圆
    CGRect rectangle = CGRectMake(100, 100, 200, 200);
    CGContextAddEllipseInRect(context, rectangle);
    CGContextStrokePath(context);

    // 填充
    // 1、设置填充颜色
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
    // 2、填充椭圆
    CGContextFillEllipseInRect(context, rectangle);

}

绘制直线

- (void)drawRect:(CGRect)rect {

    // 获取上下文(画布)
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 设置线条宽度
    CGContextSetLineWidth(context, 3.0);
    // 设置线条颜色
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
    // 确定第一个点
    CGContextMoveToPoint(context, 100, 100);
    // 确定第二个点
    CGContextAddLineToPoint(context, 200, 300);
    // 开始绘图
    CGContextStrokePath(context);   
}

绘制椭圆

- (void)drawRect:(CGRect)rect {

    // 获取上下文(画布)
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 设置线条宽度
    CGContextSetLineWidth(context, 3.0);
    // 设置线条颜色
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);

    // 创建一个椭圆,如果 width = height 则是一个圆
    CGRect rectangle = CGRectMake(100, 100, 200, 200);

    CGContextAddEllipseInRect(context, rectangle);

    CGContextStrokePath(context);

}

绘制三角形

- (void)drawRect:(CGRect)rect {

    // 获取上下文(画布)
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 设置线条宽度
    CGContextSetLineWidth(context, 3.0);
    // 设置线条颜色
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);

    // 创建三个点
    CGPoint point1 = CGPointMake(CGRectGetMidX(self.bounds),
                                 CGRectGetMidY(self.bounds) - 80);
    CGPoint point2 = CGPointMake(CGRectGetMidX(self.bounds) - 80,
                                 CGRectGetMidY(self.bounds) + 100);
    CGPoint point3 = CGPointMake(CGRectGetMidX(self.bounds) + 80,
                                 CGRectGetMidY(self.bounds) + 100);

    // 连接三个点
    // 1、设置起点
    CGContextMoveToPoint(context, point1.x, point1.y);
    // 2、设置连接点
    CGContextAddLineToPoint(context, point2.x, point2.y);
    CGContextAddLineToPoint(context, point3.x, point3.y);
    CGContextAddLineToPoint(context, point1.x, point1.y);
    // 绘图
    CGContextStrokePath(context);

}

绘制虚线

- (void)drawRect:(CGRect)rect {

    // 获取上下文(画布)
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 设置线条宽度
    CGContextSetLineWidth(context, 3.0);
    // 设置线条颜色
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);

    // lengths 指明虚线如何交替绘制
    // lengths {10, 10}表示先绘制10个点,再跳过10个点,再绘制10个点,如此反复绘制;
    // lengths {5, 10, 5}表示先绘制5个点,再跳过10个点,再绘制5个点,再跳过5个点,如此反复绘制;

    CGFloat lengths[] = {10, 10};

    // 第1个参数:上下文
    // 第2个参数:phase值,如果设值为5,则在绘制第一段的时候执行(n - 5)个点,n为虚线交替绘制方式第1个元素值。
    // 第3个参数:虚线交替绘制方式
    // 第4个参数:虚线交替绘制方式集合元素个数
    CGContextSetLineDash(context, 0, lengths, 2);

    // 设置虚线起点
    CGContextMoveToPoint(context, 100, 100);
    // 设置虚线终点
    CGContextAddLineToPoint(context, 300, 300);
    // 开始绘制
    CGContextStrokePath(context);

}

绘制弧线

方法1:

- (void)drawRect:(CGRect)rect {

    // 获取上下文(画布)
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 设置线条宽度
    CGContextSetLineWidth(context, 3.0);
    // 设置线条颜色
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);

    // 设置圆心
    CGPoint centerPoint = {200, 300};
    // 设置半径
    CGFloat radius = 100;
    // 设置起始角度
    CGFloat startAngle = 0;
    // 设置结束角度
    CGFloat endAngle = M_PI;
    // 设置绘制方向:1为顺时针, 0为逆时针
    int clockwise = 1;

    // 绘制弧线
    // 第1个参数:上下文
    // 第2个参数:圆心.x
    // 第3个参数:圆心.y
    // 第4个参数:半径
    // 第5个参数:起始角度
    // 第6个参数:结束角度
    // 第7个参数:旋转方向
    CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, startAngle, endAngle, clockwise);
    CGContextStrokePath(context);

}

方法2:

- (void)drawRect:(CGRect)rect {

    // 获取上下文(画布)
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 设置线条宽度
    CGContextSetLineWidth(context, 3.0);
    // 设置线条颜色
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);

    // 通过指定2个切点,还有角度,调用CGContextAddArcToPoint()绘制。
    // 圆弧起点
    CGPoint firstPoint = {100 ,300};
    CGPoint middlePoint = {200 ,200};
    CGPoint endPoint = {300 ,300};

    CGContextMoveToPoint(context, firstPoint.x, firstPoint.y);

    CGContextAddArcToPoint(context, middlePoint.x, middlePoint.y, endPoint.x, endPoint.y, 130);

    CGContextStrokePath(context);

}

绘制曲线

- (void)drawRect:(CGRect)rect {

    // 获取上下文(画布)
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 设置线条宽度
    CGContextSetLineWidth(context, 3.0);
    // 设置线条颜色
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);

    // 创建四个点
    CGPoint firstPoint = {20, 200};
    CGContextMoveToPoint(context, firstPoint.x, firstPoint.y);
    // 顶峰点
    CGPoint topPoint = {90, 40};
    // 低峰点
    CGPoint bottomPoint = {230, 360};
    // 末尾点
    CGPoint endPoint = {300, 200};

    // 贝兹曲线是通过一个起始点,然后通过两个控制点,还有一个终止点,调用CGContextAddCurveToPoint()函数绘制。
    CGContextAddCurveToPoint(context, topPoint.x, topPoint.y, bottomPoint.x, bottomPoint.y, endPoint.x, endPoint.y);
    CGContextStrokePath(context);

}

注意:如果需要绘制多个峰值,可继续绘制曲线,只需将二次绘制曲线起点置为上一次曲线终点即可。

UIBezierPath 绘图

绘制多边形

- (void)drawRect:(CGRect)rect {

    // 设置画笔颜色
    [[UIColor redColor] setStroke];

    UIBezierPath * path = [[UIBezierPath alloc]init];

    // 设置起点
    [path moveToPoint:CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds))];

    // 添加点
    [path addLineToPoint:CGPointMake(100, 100)];
    [path addLineToPoint:CGPointMake(120, 80)];
    [path addLineToPoint:CGPointMake(150, 100)];

    // 封闭路径
    [path closePath];
    // 设直线条宽度
    [path setLineWidth:2];
    // 设置拐角处的效果为圆角
    [path setLineJoinStyle:kCGLineJoinRound];
    // 设置结束处的效果为圆角
    [path setLineCapStyle:kCGLineCapRound];
    // 开始绘制
    [path stroke];


    // 填充
    // 1、设置填充颜色
    [[UIColor brownColor] setFill];
    // 2、开始填充
    [path fill];
}

绘制弧形

- (void)drawRect:(CGRect)rect {

    // 设置填充颜色
    [[UIColor redColor] setFill];

    UIBezierPath * path = [[UIBezierPath alloc]init];

    // 设置圆心
    [path moveToPoint:CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds))];

    // 画弧
    CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));

    [path addArcWithCenter:center // 圆心
                    radius:80     // 半径
                startAngle:0      // 起始角度
                  endAngle:M_PI_2 // 结束角度
                 clockwise:YES];  // 是否顺时针
    // 封闭路径
    [path closePath];
    // 填充
    [path fill];
}

注意:以上绘图直接在drawRect方法里面执行,如果不在此方法中执行,需要通过CAShapeLayer类渲染。

拓展

CAShapeLayer实现动画绘制

  • 效果展示

    这里写图片描述

  • 代码示例

- (void)viewDidLoad {
    [super viewDidLoad];

    CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
    shapeLayer.frame = CGRectMake(0, 0, 150, 150);
    // 使用position来确定layer的位置
    shapeLayer.position = self.view.center;
    // clockwise控制顺时针或逆时针
    // 绘制路径,画圆
    shapeLayer.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetMidX(shapeLayer.bounds), CGRectGetMidY(shapeLayer.bounds)) radius:CGRectGetMidX(shapeLayer.bounds) startAngle:0 endAngle:2 * M_PI clockwise:YES].CGPath;
    // 设置图层的路径渲染颜色
    shapeLayer.strokeColor = [UIColor blueColor].CGColor;
    // 设置图层的填充颜色
    shapeLayer.fillColor = [UIColor clearColor].CGColor;
    // 设置路径宽度
    shapeLayer.lineWidth = 2;
    [self.view.layer addSublayer:shapeLayer];

    // 使用高级动画中的基本动画,做渲染的关键字为strokeEnd
    CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    // 设置持续时间
    basicAnimation.duration = 3;
    // 设置起始帧
    basicAnimation.fromValue = @0;
    // 设置结束帧
    basicAnimation.toValue = @1;
    // 设置重复次数
    basicAnimation.repeatCount = HUGE_VAL;
    // 设置是否反向执行
    basicAnimation.autoreverses = NO;
    // 用一个字符串标识这个动画,内容是任意的。
    [shapeLayer addAnimation:basicAnimation forKey:@"strokeEnd"];

}

触摸绘图

  • 效果展示

    这里写图片描述

  • 代码示例

#import "DrawingView.h"

enum {
    undoTag = 100, clearTag
};

@interface DrawingView () {
    NSMutableArray *_lines; /**< 存储绘制的线 */
}

@end

@implementation DrawingView

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

        self.backgroundColor = [UIColor whiteColor];

        // 初始化集合
        _lines = [NSMutableArray array];

        // 撤销
        UIButton *undoButton = [UIButton buttonWithType:UIButtonTypeSystem];
        undoButton.bounds = CGRectMake(0, 0, 50, 40);
        undoButton.center = CGPointMake(self.bounds.size.width - 50, 55);
        [self setButtonAttributeWithButton:undoButton title:@"撤销" tag:undoTag];
        [self addSubview:undoButton];

        // 清空
        UIButton *clearButton = [UIButton buttonWithType:UIButtonTypeSystem];
        clearButton.bounds = CGRectMake(0, 0, 50, 40);
        clearButton.center = CGPointMake(40, 55);
        [self setButtonAttributeWithButton:clearButton title:@"清空" tag:clearTag];
        [self addSubview:clearButton];
    }
    return self;
}

- (void)drawRect:(CGRect)rect {

    // 异常处理
    if (_lines.count == 0) {
        return;
    }

    // 解决点点击之后再绘制奔溃的问题
    [_lines removeObject:@[]];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 3.0);
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);

    // 步骤:取出一条线 -》 取得线上的每一个点 -》绘图
    for (int i = 0; i < _lines.count; i++) {
        NSMutableArray *points = _lines[i];
        for (int j = 0; j < points.count - 1; j++) {

            CGPoint currentPoint = [points[j] CGPointValue];
            CGPoint nextPoint = [points[j + 1] CGPointValue];

            // 连接两点
            CGContextMoveToPoint(context, currentPoint.x, currentPoint.y);
            CGContextAddLineToPoint(context, nextPoint.x, nextPoint.y);
        }
    }
    // 开始绘制
    CGContextStrokePath(context);

}

#pragma mark - Touches methods
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    NSMutableArray *newPoints = [NSMutableArray array];

    [_lines addObject:newPoints];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    NSValue *value = [NSValue valueWithCGPoint:point];

    [_lines.lastObject addObject:value];
    // 调用此方法会直接调用drawRect方法
    [self setNeedsDisplay];

}

#pragma mark - Private methods
- (void)setButtonAttributeWithButton:(UIButton *)button title:(NSString *)title tag:(NSInteger)tag {
    button.tag = tag;
    button.layer.borderWidth = 0.5;
    button.layer.borderColor = [UIColor blackColor].CGColor;
    button.layer.cornerRadius = 6;
    [button setTitle:title forState:UIControlStateNormal];
    [button addTarget:self action:@selector(respondsToButton:) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark - responds events
- (void)respondsToButton:(UIButton *)sender {
    switch (sender.tag) {
        case undoTag: {
            [_lines removeLastObject];
            [self setNeedsDisplay];
        }
            break;
        case clearTag: {
            [_lines removeAllObjects];
            [self setNeedsDisplay];
        }

        default:
            break;
    }
}

@end

注意:DrawingViewUIView的子类;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值