使用Core Graphics进行绘图开发
在开发绘图应用时,Core Graphics是一个强大的工具。本文将详细介绍如何使用Core Graphics进行绘图应用的开发,包括随机颜色生成、常量定义、视图骨架实现、界面设置、动作方法实现以及绘图代码添加等方面。
随机颜色生成
为了生成随机颜色,我们使用
arc4random()
函数为每个颜色分量生成一个随机浮点数。每个颜色分量的值需要在0.0到1.0之间,因此我们将随机值除以256取余数,得到0到255之间的数,再除以255。这是因为iOS上的Quartz 2D为每个颜色分量支持256种不同的强度,使用255可以确保我们有机会随机选择其中任何一种。最后,我们使用这三个随机分量创建一个新颜色,并将alpha值设置为1.0,使所有生成的颜色都是不透明的。
定义应用常量
我们定义了两个枚举类型来表示用户可以通过分段控制器选择的选项。一个表示应用中可用的形状选项,另一个表示可用的颜色选项。这些常量的值对应于我们将在应用中创建的两个分段控件的分段。
typedef NS_ENUM(NSInteger, ShapeType) {
kLineShape = 0,
kRectShape,
kEllipseShape,
kImageShape
};
typedef NS_ENUM(NSInteger, ColorTabIndex) {
kRedColorTab = 0,
kBlueColorTab,
kYellowColorTab,
kGreenColorTab,
kRandomColorTab
};
实现QuartzFunView骨架
我们将在
UIView
的子类中进行绘图,因此需要设置这个类。首先,在
QuartzFunView.h
文件中添加必要的代码,导入
Constants.h
头文件,并声明三个属性来跟踪用户想要绘制的形状、是否请求随机颜色以及当前选择的颜色。
#import <UIKit/UIKit.h>
#import "Constants.h"
@interface QuartzFunView : UIView
@property (assign, nonatomic) ShapeType shapeType;
@property (assign, nonatomic) BOOL useRandomColor;
@property (strong, nonatomic) UIColor *currentColor;
@end
然后,在
QuartzFunView.m
文件中进行一些更改。导入
UIColor+Random.h
头文件以生成随机颜色,并创建类扩展,添加三个更多的属性来跟踪用户手指在屏幕上的拖动位置和要绘制的图像。
#import "UIColor+Random.h"
@interface QuartzFunView ()
@property (assign, nonatomic) CGPoint firstTouchLocation;
@property (assign, nonatomic) CGPoint lastTouchLocation;
@property (strong, nonatomic) UIImage *image;
@end
接下来,重写
initWithCoder:
方法,设置初始颜色为红色,初始化
useRandomColor
为
NO
,并加载要绘制的图像文件。
- (id)initWithCoder:(NSCoder*)coder {
if (self = [super initWithCoder:coder]) {
_currentColor = [UIColor redColor];
_useRandomColor = NO;
_image = [UIImage imageNamed:@"iphone"] ;
}
return self;
}
最后,添加三个方法来响应用户的触摸事件。
#pragma mark - Touch Handling
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.useRandomColor) {
self.currentColor = [UIColor randomColor];
}
UITouch *touch = [touches anyObject];
self.firstTouchLocation = [touch locationInView:self];
self.lastTouchLocation = [touch locationInView:self];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
self.lastTouchLocation = [touch locationInView:self];
[self setNeedsDisplay];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
self.lastTouchLocation = [touch locationInView:self];
[self setNeedsDisplay];
}
这些方法的工作原理如下:
-
touchesBegan:withEvent:
:当用户的手指首次触摸屏幕时调用。如果用户选择了随机颜色,我们会更改颜色,然后存储当前位置,并指示视图需要重绘。
-
touchesMoved:withEvent:
:当用户在屏幕上拖动手指时持续调用。我们只需要存储新位置并指示屏幕需要重绘。
-
touchesEnded:withEvent:
:当用户将手指从屏幕上抬起时调用。我们存储最终位置并指示视图需要重绘。
创建和连接出口和动作
在开始绘图之前,我们需要在GUI中添加分段控件,并连接动作和出口。具体步骤如下:
1. 打开
Main.storyboard
,将视图的类从
UIView
更改为
QuartzFunView
。
2. 使用对象库找到一个分段控件,将其拖到视图顶部,状态栏下方,并大致居中。
3. 选择分段控件,将分段数量从2更改为5,并依次将每个分段的标签更改为Red、Blue、Yellow、Green和Random。
4. 应用布局约束:
- 在文档大纲中,从分段控件项Control-drag到Quartz Fun View项,释放鼠标并选择Top Space to Top Layout Guide。
- 再次Control-drag,选择Center Horizontally in Container。
- 点击编辑区域底部的Pin按钮,勾选Width复选框并输入290,然后点击Add 1 constraint。
- 在文档大纲中选择视图控制器图标,然后在故事板编辑器中点击Resolve Auto Layout Issues按钮并选择Update Frames。
5. 打开辅助编辑器,选择
ViewController.m
。从文档大纲中的分段控件Control-drag到
ViewController.m
文件,在
@interface
和
@end
之间创建一个新的出口,命名为
colorControl
。
6. 添加一个动作:选择
Main.storyboard
,从分段控件Control-drag到
ViewController.m
文件,直接在
@end
声明上方创建一个动作,将连接类型更改为Action,名称更改为
changeColor
,类型更改为
UISegmentedControl
。
7. 添加第二个分段控件用于选择形状:
- 将分段控件拖到视图底部。
- 将分段数量从2更改为4,依次将每个分段的标题更改为Line、Rect、Ellipse和Image。
- 应用布局约束,步骤与颜色选择分段控件类似。
- 打开
ViewController.m
,从新的分段控件Control-drag到
ViewController.m
文件,在
@end
行上方创建一个动作,将连接类型更改为Action,名称更改为
changeShape
,类型更改为
UISegmentedControl
。
实现动作方法
在
ViewController.m
文件中,我们需要导入
Constants.h
和
QuartzFunView.h
头文件,然后实现
changeColor:
和
changeShape:
方法。
#import "Constants.h"
#import "QuartzFunView.h"
- (IBAction)changeColor:(UISegmentedControl *)sender {
QuartzFunView *funView = (QuartzFunView *)self.view;
ColorTabIndex index = [sender selectedSegmentIndex];
switch (index) {
case kRedColorTab:
funView.currentColor = [UIColor redColor];
funView.useRandomColor = NO;
break;
case kBlueColorTab:
funView.currentColor = [UIColor blueColor];
funView.useRandomColor = NO;
break;
case kYellowColorTab:
funView.currentColor = [UIColor yellowColor];
funView.useRandomColor = NO;
break;
case kGreenColorTab:
funView.currentColor = [UIColor greenColor];
funView.useRandomColor = NO;
break;
case kRandomColorTab:
funView.useRandomColor = YES;
break;
default:
break;
}
}
- (IBAction)changeShape:(UISegmentedControl *)sender {
[(QuartzFunView *)self.view setShapeType:[sender selectedSegmentIndex]];
self.colorControl.hidden = [sender selectedSegmentIndex] == kImageShape;
}
在
changeColor:
方法中,我们根据用户选择的分段创建一个新颜色,并设置
currentColor
属性。如果选择了随机颜色,我们将
useRandomColor
属性设置为
YES
。在
changeShape:
方法中,我们根据所选分段设置形状类型,并根据是否选择了Image分段隐藏或显示颜色选择控件。
编译并运行应用,此时虽然还不能在屏幕上绘制形状,但分段控件应该可以正常工作,当点击底部控件中的Image分段时,颜色控件应该会消失。
添加Quartz 2D绘图代码
我们准备添加绘图代码,首先从绘制一条线开始。
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, self.currentColor.CGColor);
switch (self.shapeType) {
case kLineShape:
CGContextMoveToPoint(context,
self.firstTouchLocation.x,
self.firstTouchLocation.y);
CGContextAddLineToPoint(context,
self.lastTouchLocation.x,
self.lastTouchLocation.y);
CGContextStrokePath(context);
break;
case kRectShape:
break;
case kEllipseShape:
break;
case kImageShape:
break;
default:
break;
}
}
在这个方法中,我们首先获取当前上下文的引用,然后设置线宽和描边颜色。使用
switch
语句根据形状类型跳转到相应的代码。对于
kLineShape
,我们告诉图形上下文从用户首次触摸的位置开始创建路径,然后绘制一条线到用户最后触摸的位置,最后描边路径使线显示在屏幕上。
接下来,我们添加绘制矩形和椭圆的代码:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, self.currentColor.CGColor);
CGContextSetFillColorWithColor(context, self.currentColor.CGColor);
CGRect currentRect = CGRectMake(self.firstTouchLocation.x,
self.firstTouchLocation.y,
self.lastTouchLocation.x -
self.firstTouchLocation.x,
self.lastTouchLocation.y -
self.firstTouchLocation.y);
switch (self.shapeType) {
case kLineShape:
CGContextMoveToPoint(context,
self.firstTouchLocation.x,
self.firstTouchLocation.y);
CGContextAddLineToPoint(context,
self.lastTouchLocation.x,
self.lastTouchLocation.y);
CGContextStrokePath(context);
break;
case kRectShape:
CGContextAddRect(context, currentRect);
CGContextDrawPath(context, kCGPathFillStroke);
break;
case kEllipseShape:
CGContextAddEllipseInRect(context, currentRect);
CGContextDrawPath(context, kCGPathFillStroke);
break;
case kImageShape:
break;
default:
break;
}
}
因为我们想要绘制椭圆和矩形的轮廓并填充其内部,所以我们添加了一个调用
CGContextSetFillColorWithColor
来设置填充颜色。我们声明了一个
CGRect
变量
currentRect
来保存用户拖动所描述的矩形。对于矩形和椭圆,我们分别使用
CGContextAddRect
和
CGContextAddEllipseInRect
将它们添加到上下文中,然后使用
CGContextDrawPath
进行绘制。
通过以上步骤,我们可以逐步实现一个功能丰富的绘图应用,用户可以选择不同的形状和颜色进行绘图。
使用Core Graphics进行绘图开发(续)
绘制图像
接下来,我们将添加绘制图像的代码到
drawRect:
方法中。在
switch
语句里添加
kImageShape
的处理逻辑。
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, self.currentColor.CGColor);
CGContextSetFillColorWithColor(context, self.currentColor.CGColor);
CGRect currentRect = CGRectMake(self.firstTouchLocation.x,
self.firstTouchLocation.y,
self.lastTouchLocation.x -
self.firstTouchLocation.x,
self.lastTouchLocation.y -
self.firstTouchLocation.y);
switch (self.shapeType) {
case kLineShape:
CGContextMoveToPoint(context,
self.firstTouchLocation.x,
self.firstTouchLocation.y);
CGContextAddLineToPoint(context,
self.lastTouchLocation.x,
self.lastTouchLocation.y);
CGContextStrokePath(context);
break;
case kRectShape:
CGContextAddRect(context, currentRect);
CGContextDrawPath(context, kCGPathFillStroke);
break;
case kEllipseShape:
CGContextAddEllipseInRect(context, currentRect);
CGContextDrawPath(context, kCGPathFillStroke);
break;
case kImageShape:
if (self.image) {
[self.image drawInRect:currentRect];
}
break;
default:
break;
}
}
在
kImageShape
的处理中,我们首先检查
self.image
是否存在,如果存在则使用
drawInRect:
方法将图像绘制在由
currentRect
定义的矩形区域内。
总结与回顾
整个绘图应用的开发过程可以总结为以下几个关键步骤,下面用表格展示:
|步骤|操作内容|
| ---- | ---- |
|随机颜色生成|使用
arc4random()
函数为每个颜色分量生成随机浮点数,处理后创建新颜色并设置alpha值为1.0|
|定义应用常量|声明
ShapeType
和
ColorTabIndex
两个枚举类型,对应形状和颜色选项|
|实现QuartzFunView骨架|在
QuartzFunView.h
和
.m
文件中声明属性、重写初始化方法和添加触摸事件处理方法|
|创建和连接出口和动作|在
Main.storyboard
中添加分段控件,设置布局约束,连接出口和动作到
ViewController.m
|
|实现动作方法|在
ViewController.m
中实现
changeColor:
和
changeShape:
方法,根据用户选择设置颜色和形状|
|添加绘图代码|在
QuartzFunView.m
的
drawRect:
方法中添加绘制线、矩形、椭圆和图像的代码|
下面是整个开发流程的mermaid流程图:
graph LR
A[随机颜色生成] --> B[定义应用常量]
B --> C[实现QuartzFunView骨架]
C --> D[创建和连接出口和动作]
D --> E[实现动作方法]
E --> F[添加绘图代码]
通过以上一系列的操作,我们成功地使用Core Graphics开发了一个绘图应用。用户可以通过分段控件选择不同的形状(线、矩形、椭圆、图像)和颜色(红、蓝、黄、绿、随机)进行绘图。在开发过程中,我们利用了Core Graphics的强大功能,如获取图形上下文、设置线宽和颜色、绘制路径等。同时,通过处理用户的触摸事件,我们能够准确地记录用户的操作位置,从而实现根据用户的手势绘制相应的图形。
这个绘图应用不仅展示了Core Graphics在iOS开发中的应用,还体现了如何通过合理的代码结构和布局约束来实现一个功能丰富且用户体验良好的应用。开发者可以根据自己的需求进一步扩展这个应用,例如添加更多的形状和颜色选项,或者实现图形的编辑和保存功能等。
超级会员免费看
11

被折叠的 条评论
为什么被折叠?



