首页 iOS开发:使用Core Graphics绘图和图像处理
文章
取消

iOS开发:使用Core Graphics绘图和图像处理

在iOS开发中,绘制图形和图像处理是非常重要的一部分。Core Graphics框架提供了一系列强大的API,用于创建高质量的图形和进行复杂的图像处理。在本文中,我们将深入探讨Core Graphics框架,并提供一些实用的代码示例。

什么是Core Graphics框架?

Core Graphics框架是一个基于C语言的框架,它提供了一种绘制2D图形的方式。它支持多种颜色空间、路径绘制和渐变等功能,并且可以用于创建PDF和PostScript文件,以及直接在屏幕上呈现图形。

Core Graphics框架也称为Quartz2D,其主要功能包括:

  • 绘制线条、圆形、矩形和其他形状
  • 渲染图像和文本
  • 创建阴影和渐变效果
  • 裁剪图形
  • 处理PDF
  • 屏幕截图
  • 缩放裁剪图片
  • 绘制统计图(折线图、柱状图、扇形图)

Core Graphics框架的基本概念

在开始使用Core Graphics框架之前,需要了解一些基本概念:

图形上下文(Graphics Context)

图形上下文是一组参数,用于指定如何绘制图形。它包含了当前的绘图状态、绘图目标和其他必要的信息。你会发现很多Core Graphics函数都需要一个CGContextRef类型的参数,这就是图形上下文。

使用自己创建的上下文性能效率不高,通常创建一个UIView的子类以获得它的上下文。在UIView中调用 drawRect: 方法时,会自动准备好一个图形上下文,可以通过调用 UIGraphicsGetCurrentContext() 来获取。开发者只能获取,不能自己重新创建,在该图层上下文中绘制的图形,最终会通过CALayer显示出来。 因为它是运行期间绘制图片,我们可以动态的做一些额外的操作。

路径(Path)

路径是由线条和曲线构成的集合,描述了一种特定的形状。通过绘制路径,你可以创建自定义形状,例如圆形、矩形、多边形和任意线条。绘图步骤通常包括以下几个步骤:

  1. 获取图形上下文
  2. 描述绘画内容 
    a. 创建图形路径 
    b. 创建图形起始点 
    c. 添加图形的终点
  3. 把绘画内容添加到图形上下文
  4. 设置图形上下文的状态(颜色和线条宽度等)
  5. 渲染图形上下文

上下文状态(Graphics State)

上下文状态是指图形上下文的所有属性,如颜色、线条宽度、字体、阴影等。当你更改上下文状态时,所有后续的绘图操作都将受到影响。因此,在更改上下文状态之前,最好保留原有的状态,以便在需要时进行恢复。

颜色空间(Color Space)

颜色空间是一种映射颜色值的数学模型。它定义了颜色由哪些元素组成,以及如何将这些元素转换为设备上的实际颜色。Core Graphics提供了许多不同的颜色空间,如RGB、CMYK、灰度和带Alpha通道的空间。

渐变(Gradient)

渐变是一种从一个颜色到另一个颜色过渡的效果。它可以是线性的或径向的,并且可以在一段距离内平滑地过渡。Core Graphics提供了许多不同的渐变类型,如线性渐变、径向渐变和轴向渐变。

Core Graphics框架的代码示例

下面是一些使用Core Graphics框架进行图形绘制的代码示例,其中包括画线、画圆和渐变等。

画线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// MyView.h

#import <UIKit/UIKit.h>

@interface MyView : UIView

@end

// MyView.m

#import "MyView.h"

@implementation MyView

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
        
    // 设置起点和终点
    CGPoint startPoint = CGPointMake(50, 50);
    CGPoint endPoint = CGPointMake(350, 50);
    
    // 设置线条颜色和宽度
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    CGContextSetLineWidth(context, 3.0);
    // 创建路径并添加线条
    CGContextBeginPath(context);
    CGContextMoveToPoint(context, startPoint.x, startPoint.y);
    CGContextAddLineToPoint(context, endPoint.x, endPoint.y);

    // 绘制路径
    CGContextStrokePath(context);
}

@end

// testViewController.m

#import "testViewController.h"

@interface testViewController ()

@end

@implementation testViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    MyView *myView = [[MyView alloc] initWithFrame:CGRectMake(10, 100, 350, 350)];
    myView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:myView];
}

@end

画圆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();

    // 设置圆心和半径
    CGPoint center = CGPointMake(100, 100);
    CGFloat radius = 50.0;

    // 创建路径并添加圆形
    CGContextBeginPath(context);
    CGContextAddArc(context, center.x, center.y, radius, 0.0, M_PI * 2, YES);

    // 设置填充颜色和绘制路径
    CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
    CGContextFillPath(context);
}

渐变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();

    // 设置起点和终点
    CGPoint startPoint = CGPointMake(50, 50);
    CGPoint endPoint = CGPointMake(350, 50);

    // 创建颜色空间
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // 设置渐变色的颜色数组和位置数组
    NSArray *colors = @[(id)[UIColor redColor].CGColor, (id)[UIColor greenColor].CGColor];
    CGFloat locations[] = {0.0, 1.0};

    // 创建渐变对象并设置路径
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
    CGContextBeginPath(context);
    CGContextMoveToPoint(context, startPoint.x, startPoint.y);
    CGContextAddLineToPoint(context, endPoint.x, endPoint.y);

    // 将渐变应用于路径
    CGContextSaveGState(context);
    CGContextReplacePathWithStrokedPath(context);
    CGContextClip(context);
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
    CGContextRestoreGState(context);

    // 释放内存
    CGColorSpaceRelease(colorSpace);
    CGGradientRelease(gradient);
}

绘制五角星

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 设置起点和半径
    CGPoint center = CGPointMake(100, 100);
    CGFloat radius = 50.0;
    
    // 计算五个顶点坐标
    CGPoint points[5];
    CGFloat angle = -M_PI_2;
    CGFloat delta = 2 * M_PI / 5.0;
    for (int i = 0; i < 5; i++) {
        CGFloat x = center.x + cos(angle) * radius;
        CGFloat y = center.y + sin(angle) * radius;
        points[i] = CGPointMake(x, y);
        angle += delta;
    }
    
    // 创建路径并添加五角星
    CGContextBeginPath(context);
    CGContextMoveToPoint(context, points[0].x, points[0].y);
    for (int i = 1; i < 5; i++) {
        CGContextAddLineToPoint(context, points[i].x, points[i].y);
    }
    CGContextClosePath(context);
    
    // 设置填充颜色和绘制路径
    CGContextSetFillColorWithColor(context, [UIColor yellowColor].CGColor);
    CGContextFillPath(context);
}

绘制心形图案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 设置起点和大小
    CGPoint center = CGPointMake(100, 100);
    CGSize size = CGSizeMake(80, 80);
    
    // 创建路径并添加心形
    CGContextBeginPath(context);
    CGContextMoveToPoint(context, center.x, center.y - size.height / 4);
    CGContextAddCurveToPoint(context, center.x + size.width / 2, center.y - size.height / 2,
                            center.x + size.width / 2, center.y + size.height / 4,
                            center.x, center.y + size.height / 2);
    CGContextAddCurveToPoint(context, center.x - size.width / 2, center.y + size.height / 4,
                            center.x - size.width / 2, center.y - size.height / 2,
                            center.x, center.y - size.height / 4);
    CGContextClosePath(context);
    
    // 设置填充颜色和绘制路径
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
    CGContextFillPath(context);
}

给图片加水印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 加载图像并绘制
    UIImage *image = [UIImage imageNamed:@"image.png"];
    [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
    
    // 绘制文本
    NSString *text = @"这是图片上的水印文字";
    NSDictionary *attributes = @{NSFontAttributeName: [UIFont systemFontOfSize:20.0],
                                 NSForegroundColorAttributeName: [UIColor whiteColor]};
    CGSize textSize = [text sizeWithAttributes:attributes];
    CGRect textRect = CGRectMake((image.size.width - textSize.width) / 2.0, image.size.height - textSize.height - 10.0, textSize.width, textSize.height);
    [text drawInRect:textRect withAttributes:attributes];
}

创建阴影

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 设置起点和大小
    CGPoint center = CGPointMake(100, 100);
    CGSize size = CGSizeMake(80, 80);
    
    // 创建路径并添加矩形
    CGContextBeginPath(context);
    CGContextAddRect(context, CGRectMake(center.x - size.width / 2, center.y - size.height / 2, size.width, size.height));
    
    // 设置阴影属性并绘制路径
    CGContextSaveGState(context);
    CGContextSetShadowWithColor(context, CGSizeMake(5, 5), 10.0, [UIColor grayColor].CGColor);
    CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
    CGContextFillPath(context);
    CGContextRestoreGState(context);
}

绘制PDF文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (void)drawRect:(CGRect)rect {
    // 设置页面大小和边距
    CGRect pageRect = CGRectMake(0, 0, 612, 792); // Letter size with 1 inch margin
    UIEdgeInsets pageMargins = UIEdgeInsetsMake(72, 72, 72, 72); // 1 inch margin

    // 创建PDF文档
    NSString *pdfPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"MyPDF.pdf"];
    CFURLRef pdfURL = (__bridge CFURLRef)[NSURL fileURLWithPath:pdfPath];
    CGContextRef context = CGPDFContextCreateWithURL(pdfURL, &pageRect, NULL);

    // 开始页面
    CGContextBeginPage(context, &pageRect);

    // 绘制内容
    NSString *text = @"Hello World!";
    UIFont *font = [UIFont systemFontOfSize:20.0];
    NSDictionary *attributes = @{NSFontAttributeName: font};
    CGSize textSize = [text sizeWithAttributes:attributes];
    CGRect textRect = CGRectMake(pageMargins.left, pageMargins.top, pageRect.size.width - pageMargins.left - pageMargins.right,
    pageRect.size.height - pageMargins.top - pageMargins.bottom);
    [text drawInRect:textRect withAttributes:attributes];

    // 结束页面并释放内存
    CGContextEndPage(context);
    CGContextRelease(context);
}

屏幕截图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- (void)screenshot {
    // 开启一个位图上下文
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);

    // 获取位图上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 把屏幕上的图层渲染到图形上下文
    [self.view.layer renderInContext:ctx];

    // 从位图上下文获取图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    // 关闭上下文
    UIGraphicsEndImageContext();

    // 存储图片
    // image转data,compressionQuality:图片质量0-1
    NSData *data = UIImageJPEGRepresentation(image,1);
    [data writeToFile:@"/Users/user/Desktop/img.png" atomically:YES];
}

缩放裁剪图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 加载UIImage并绘制
    UIImage *image = [UIImage imageNamed:@"image.png"];
//    [image drawInRect:self.bounds];
    
    // 计算圆形路径并设置裁剪区域
    CGFloat radius = 50.0;
    CGFloat centerX = 100;
    CGFloat centerY = 100;
    CGContextAddArc(context, centerX, centerY, radius, 0, M_PI*2, YES);
    CGContextClip(context);
    
    // 绘制裁剪后的图像
    CGRect imageRect = CGRectMake(centerX - radius, centerY - radius, radius * 2, radius * 2);
    [image drawInRect:imageRect];
}

折线图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
- (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 设置坐标轴范围
    CGFloat padding = 20.0;
    CGFloat xStart = padding + 35.0; // x轴起点
    CGFloat yStart = self.bounds.size.height - padding - 30.0; // y轴起点
    CGFloat xEnd = self.bounds.size.width - padding;
    CGFloat yEnd = padding; // y轴终点
    CGFloat xRange = xEnd - xStart;
    CGFloat yRange = yStart - yEnd;
    
    NSArray *dataArray = @[@"23", @"35", @"5", @"56",@"25",];
    int maxValue = 100;
    
    // 绘制x轴刻度
    CGFloat xSpacing = xRange / (dataArray.count - 1);
    for (int i = 0; i < dataArray.count; i++) {
        NSString *text = [NSString stringWithFormat:@"%d", i];
        CGSize textSize = [text sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
        CGPoint textPoint = CGPointMake(xStart + xSpacing * i - textSize.width / 2.0, yStart + 5.0);
        [text drawAtPoint:textPoint withAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
    }
    
    // 绘制y轴刻度
    CGFloat ySpacing = yRange / 5.0;
    for (int i = 0; i <= 5; i++) {
        NSString *text = [NSString stringWithFormat:@"%.0f", maxValue / 5.0 * i];
        CGSize textSize = [text sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
        CGPoint textPoint = CGPointMake(xStart - textSize.width - 5.0, yStart - ySpacing * i - textSize.height / 2.0);
        [text drawAtPoint:textPoint withAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
        
        CGContextSetStrokeColorWithColor(context, [UIColor lightGrayColor].CGColor);
        CGContextSetLineWidth(context, 1.0);
        CGContextMoveToPoint(context, xStart, yStart - ySpacing * i);
        CGContextAddLineToPoint(context, xEnd, yStart - ySpacing * i);
        CGContextStrokePath(context);
    }
    
    // 绘制坐标轴
    CGContextSetLineWidth(context, 2.0);
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextMoveToPoint(context, xEnd, yStart);
    CGContextAddLineToPoint(context, xStart, yStart);
    CGContextAddLineToPoint(context, xStart, yEnd);
    CGContextStrokePath(context);
    
    // 绘制数据线
    CGContextSetLineWidth(context, 1.0);
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
    CGContextBeginPath(context);
    for (int i = 0; i < dataArray.count; i++) {
        CGFloat xValue = xStart + xRange / (dataArray.count - 1) * i;
        CGFloat yValue = yStart - yRange / maxValue * [dataArray[i] floatValue];
        if (i == 0) {
            CGContextMoveToPoint(context, xValue, yValue);
        } else {
            CGContextAddLineToPoint(context, xValue, yValue);
        }
        // 标注数据点数值
        NSString *valueText = [NSString stringWithFormat:@"%d", [dataArray[i] intValue]];
        CGSize valueSize = [valueText sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
        CGPoint valuePoint = CGPointMake(xValue - valueSize.width / 2.0, yValue - valueSize.height - 3.0);
        [valueText drawAtPoint:valuePoint withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0], NSForegroundColorAttributeName: [UIColor blueColor]}];
    }
    CGContextStrokePath(context);
}

柱状图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 设置坐标轴范围
    CGFloat padding = 20.0;
    CGFloat xStart = padding + 35.0; // x轴起点
    CGFloat yStart = self.bounds.size.height - padding - 30.0; // y轴起点
    CGFloat xEnd = self.bounds.size.width - padding;
    CGFloat yEnd = padding; // y轴终点
    CGFloat xRange = xEnd - xStart;
    CGFloat yRange = yStart - yEnd;
    
    NSArray *dataArray = @[@"23", @"35", @"5", @"56",@"25",];
    int maxValue = 100;
    // 绘制x轴刻度
    CGFloat xSpacing = (xRange - padding * 2) / (dataArray.count - 1);
    for (int i = 0; i < dataArray.count; i++) {
        NSString *text = [NSString stringWithFormat:@"%d", i];
        CGSize textSize = [text sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
        CGPoint textPoint = CGPointMake(padding + xStart + xSpacing * i - textSize.width / 2.0, yStart + 5.0);
        [text drawAtPoint:textPoint withAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
    }
    
    // 绘制y轴刻度
    CGFloat ySpacing = yRange / 5.0;
    for (int i = 0; i <= 5; i++) {
        NSString *text = [NSString stringWithFormat:@"%.0f", maxValue / 5.0 * i];
        CGSize textSize = [text sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
        CGPoint textPoint = CGPointMake(xStart - textSize.width - 5.0, yStart - ySpacing * i - textSize.height / 2.0);
        [text drawAtPoint:textPoint withAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
        
        CGContextSetStrokeColorWithColor(context, [UIColor lightGrayColor].CGColor);
        CGContextSetLineWidth(context, 1.0);
        CGContextMoveToPoint(context, xStart, yStart - ySpacing * i);
        CGContextAddLineToPoint(context, xEnd, yStart - ySpacing * i);
        CGContextStrokePath(context);
    }
    
    // 绘制坐标轴
    CGContextSetLineWidth(context, 2.0);
    CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextMoveToPoint(context, xStart, yStart);
    CGContextAddLineToPoint(context, xEnd, yStart);
    CGContextMoveToPoint(context, xStart, yEnd);
    CGContextAddLineToPoint(context, xStart, yStart);
    CGContextStrokePath(context);
    
    // 绘制柱子
    CGFloat barWidth = xSpacing / 2.0;
    for (int i = 0; i < dataArray.count; i++) {
        CGFloat xValue = padding + xStart + xSpacing * i - barWidth / 2.0;
        CGFloat yValue = yStart - yRange / maxValue * [dataArray[i] floatValue];
        CGFloat barHeight = yStart - yValue;
        CGRect barRect = CGRectMake(xValue, yValue, barWidth, barHeight);
        CGContextAddRect(context, barRect);
        // 标注柱子数值
        NSString *valueText = [NSString stringWithFormat:@"%d", [dataArray[i] intValue]];
        CGSize valueSize = [valueText sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
        CGPoint valuePoint = CGPointMake(xValue + barWidth / 2.0 - valueSize.width / 2.0, yValue - valueSize.height - 3.0);
        [valueText drawAtPoint:valuePoint withAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0], NSForegroundColorAttributeName: [UIColor blueColor]}];
    }
    CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
    CGContextFillPath(context);
}

扇形图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 设置圆心和半径
    CGPoint center = CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0);
    CGFloat radius = MIN(center.x, center.y) - 20.0;
    
    NSArray *dataArray = @[@"23", @"35", @"5", @"12",@"25",];
    int totalValue = 100;
    // 绘制扇形
    CGFloat startAngle = 0.0;
    for (int i = 0; i < dataArray.count; i++) {
        CGFloat endAngle = startAngle + [dataArray[i] floatValue] / totalValue * M_PI * 2.0;
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
        [path addLineToPoint:center];
        [path closePath];
        
        UIColor *color = [UIColor colorWithHue:(CGFloat)i / dataArray.count saturation:1.0 brightness:1.0 alpha:1.0];
        [color setFill];
        [path fill];
        
        // 标注扇形数值
        NSString *valueText = [NSString stringWithFormat:@"%.1f%%", [dataArray[i] floatValue] / totalValue * 100.0];
        CGSize valueSize = [valueText sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0]}];
        CGFloat valueAngle = startAngle + (endAngle - startAngle) / 2.0;
        CGFloat valueRadius = radius + 20.0;
        CGPoint valuePoint = CGPointMake(center.x + cos(valueAngle) * valueRadius - valueSize.width / 2.0,
                                          center.y + sin(valueAngle) * valueRadius - valueSize.height / 2.0);
        [valueText drawAtPoint:valuePoint withAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0], NSForegroundColorAttributeName: color}];
        
        startAngle = endAngle;
    }
}
本文由作者按照 CC BY 4.0 进行授权

iOS开发:触摸事件和手势识别

iOS开发:网络通信基础