iOS图形绘制 UIBezierPath 绘制折线图、柱状图以及饼形图(感谢Mr_Wendao,如果想查看饼形图源码请点击连接,饼形图我借鉴了Mr_Wendao的代码学习,再次感谢)。
先看一下代码的效果图 如下图
下面是主要代码
在初始化的时候设置绘图类型
typedef NS_ENUM(NSInteger) {
LineChart_Type = 0,//折线图
PieChart_Type = 1, //饼形图
BarChart_Type = 2 //柱状图
}DrawViewType;
@interface AXDrawView : UIView<CAAnimationDelegate>
//自定义初始化方法
-(id)initWithFrame:(CGRect)frame type:(DrawViewType)type;
//绘图类型
@property(nonatomic ,assign)DrawViewType drawType;
//折线图数据数组
@property(nonatomic ,strong)NSMutableArray *arrayPoint;
//折线图开始点
@property(nonatomic ,assign)CGPoint startPint;
//折线图结束点
@property(nonatomic ,assign)CGPoint endPoint;
//饼形图颜色数据
@property(nonatomic ,strong)NSArray *colorItems;
@end
下面是实现代码
//图标上下左右边距
#define UP 10.0
#define BELOW 30.0
#define LEFT 30.0
#define RIGHT 10.0
自定义初始化方法
-(id)initWithFrame:(CGRect)frame type:(DrawViewType)type
{
self = [super initWithFrame:frame];
if (self) {
if (!_scaleArray) {
_scaleArray = [[NSArray alloc] initWithObjects:@"iOS",@"Java",@"PHP",@"HTML",@"Android",@"C语言",@"C++", nil];
}
_drawType = type;
switch (_drawType) {
case LineChart_Type:
{
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressAction:)];
[self addGestureRecognizer:longPressGesture];
}
break;
case PieChart_Type:
{
}
break;
case BarChart_Type:
{
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressAction:)];
[self addGestureRecognizer:longPressGesture];
}
break;
default:
break;
}
}
return self;
}
重写drawRect方法
- (void)drawRect:(CGRect)rect {
// Drawing code
[super drawRect:rect];
if (_drawType != PieChart_Type) {
[self drawScale];
}
switch (_drawType) {
case LineChart_Type:
{
[self drawLineChart];
}
break;
case PieChart_Type:
{
[self pieChartAction];
}
break;
case BarChart_Type:
{
[self drawBarChart];
}
break;
default:
break;
}
}
折线图以及柱状图需要坐标刻度,在绘制这两种图标是需要调用一下方法
//绘制刻度
-(void)drawScale
{
UIBezierPath *scalePath = [UIBezierPath bezierPath];
[scalePath moveToPoint:CGPointMake(30, 10)];
[scalePath addLineToPoint:CGPointMake(30, self.frame.size.height - BELOW)];
[scalePath moveToPoint:CGPointMake(30, self.frame.size.height - BELOW)];
[scalePath addLineToPoint:CGPointMake(self.frame.size.width - RIGHT, self.frame.size.height - BELOW)];
CGFloat scaleY = (self.frame.size.height - UP - BELOW) / 10.0;
for (int i = 0; i < 10; i++) {
[scalePath moveToPoint:CGPointMake(LEFT, (self.frame.size.height - BELOW) - (scaleY * i))];
[scalePath addLineToPoint:CGPointMake(LEFT + 2, (self.frame.size.height - BELOW) - (scaleY * i))];
UILabel *yLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 30, 20)];
yLabel.textColor = [UIColor redColor];
yLabel.font = [UIFont systemFontOfSize:10];
yLabel.textAlignment = NSTextAlignmentCenter;
yLabel.text = [NSString stringWithFormat:@"%d",i * 10];
yLabel.center = CGPointMake(LEFT / 2, (self.frame.size.height - BELOW) - (scaleY * i));
[self addSubview:yLabel];
}
CGFloat scaleX = (self.frame.size.width - LEFT - RIGHT) / 8.0;
for (int i = 0; i < 8; i++) {
[scalePath moveToPoint:CGPointMake((LEFT + scaleX * i), self.frame.size.height - BELOW)];
[scalePath addLineToPoint:CGPointMake((LEFT + scaleX * i), self.frame.size.height - BELOW - 2)];
if (i > 0) {
UILabel *xLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, scaleX, 20)];
xLabel.textColor = [UIColor redColor];
xLabel.font = [UIFont systemFontOfSize:10];
xLabel.textAlignment = NSTextAlignmentCenter;
xLabel.text = [_scaleArray objectAtIndex:i - 1];
xLabel.center = CGPointMake((LEFT + scaleX * i), self.frame.size.height - BELOW / 2);
[self addSubview:xLabel];
}
}
CAShapeLayer *shaperLayer = [CAShapeLayer layer];
shaperLayer.path = scalePath.CGPath;
shaperLayer.lineWidth = 1.0;
shaperLayer.lineCap = kCALineCapRound;
shaperLayer.lineJoin = kCALineJoinRound;
shaperLayer.strokeColor = [UIColor grayColor].CGColor;
[self.layer addSublayer:shaperLayer];
}
当获取到数据,需要对数据进行处理主要代码如下
//重写set方法,图标数据信息信息
-(void)setArrayPoint:(NSArray *)arrayPoint
{
if (!_arrayPoint) {
_arrayPoint = [NSMutableArray array];
}
if (_drawType == LineChart_Type) {
[_arrayPoint addObjectsFromArray:[self disposePointArray:arrayPoint]];
_startPint = CGPointFromString([_arrayPoint objectAtIndex:0]);
[self drawAction];
}else if (_drawType == PieChart_Type){
[_arrayPoint addObjectsFromArray:[self disposePointArray:arrayPoint]];
[self setNeedsDisplay];
}else if (_drawType == BarChart_Type){
[_arrayPoint addObjectsFromArray:[self disposePointArray:arrayPoint]];
_startPint = CGPointMake((self.frame.size.width - LEFT - RIGHT) / 8 + LEFT, self.frame.size.height - BELOW);
_endPoint = CGPointFromString([_arrayPoint objectAtIndex:0]);
[self setNeedsDisplay];
}
}
//处理数据获取绘图点
-(NSMutableArray *)disposePointArray:(NSArray *)array
{
if (_drawType == PieChart_Type) {
NSMutableArray *points = [NSMutableArray array];
CGFloat allFloat = 0.0;
for (NSString *string in array) {
allFloat = allFloat + [string floatValue];
}
for (NSString *string in array) {
CGFloat f = [string floatValue] / allFloat;
[points addObject:[NSString stringWithFormat:@"%.2f",f]];
}
return points;
}else{
NSMutableArray *points = [NSMutableArray array];
for (int i = 0; i < array.count; i++) {
NSString *string = [array objectAtIndex:i];
CGFloat y = (self.frame.size.height - BELOW) - ([string floatValue] / 100.0 * (self.frame.size.height - BELOW - UP));
CGPoint point = CGPointMake(LEFT + ((self.frame.size.width - LEFT - RIGHT) / 8.0 * (i + 1)), y);
[points addObject:NSStringFromCGPoint(point)];
}
return points;
}
}
//获取开始、结束点
-(void)drawAction
{
_number++;
if (_drawType == LineChart_Type) {
if (_number < _arrayPoint.count) {
NSString *pointStr = [_arrayPoint objectAtIndex:_number];
_endPoint = CGPointFromString(pointStr);
[self setNeedsDisplay];
}
}else if (_drawType == BarChart_Type){
if (_number < _arrayPoint.count) {
CGFloat scaleX = (self.frame.size.width - LEFT - RIGHT) / 8.0;
_startPint = CGPointMake((self.frame.size.width - LEFT - RIGHT) / 8 + LEFT + scaleX * _number, self.frame.size.height - BELOW);
NSString *pointStr = [_arrayPoint objectAtIndex:_number];
_endPoint = CGPointFromString(pointStr);
[self setNeedsDisplay];
}
}
}
下面的代码是绘图的主要代码
折线图
-(void)drawLineChart
{
UIBezierPath *path = [UIBezierPath bezierPath];
//绘制圆点
[path addArcWithCenter:_startPint radius:3.0 startAngle:0.0 endAngle:M_PI*2 clockwise:YES];
//设置描边宽度(为了让描边看上去更清楚)
[path setLineWidth:3.0];
//描边和填充
[path stroke];
[path fill];
//绘制折线图
[path moveToPoint:_startPint];
[path addLineToPoint:_endPoint];
path.lineJoinStyle = kCGLineJoinRound;
//设置layer层
CAShapeLayer *shaperLayer = [CAShapeLayer layer];
shaperLayer.path = path.CGPath;
shaperLayer.lineWidth = 2.0;
shaperLayer.lineCap = kCALineCapRound;
shaperLayer.lineJoin = kCALineJoinRound;
shaperLayer.strokeColor = [UIColor whiteColor].CGColor;
shaperLayer.fillColor = [UIColor whiteColor].CGColor;
//设置动画
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:NSStringFromSelector(@selector(strokeEnd))];
anim.delegate = self;
anim.fromValue = @0;
anim.toValue = @1;
anim.duration = 0.1;
[shaperLayer addAnimation:anim forKey:NSStringFromSelector(@selector(strokeEnd))];
[self.layer addSublayer:shaperLayer];
//将结束点设置为起始点
_startPint = _endPoint;
//绘制最后一个点
if (_number == _arrayPoint.count - 1) {
UIBezierPath *paths = [UIBezierPath bezierPath];
// 添加圆到path
[paths addArcWithCenter:_startPint radius:3.0 startAngle:0.0 endAngle:M_PI*2 clockwise:YES];
// 设置描边宽度(为了让描边看上去更清楚)
[paths setLineWidth:3.0];
// 描边和填充
[paths stroke];
[paths fill];
CAShapeLayer *shaperLayer = [CAShapeLayer layer];
shaperLayer.path = paths.CGPath;
shaperLayer.lineWidth = 2.0;
shaperLayer.strokeColor = [UIColor whiteColor].CGColor;
shaperLayer.fillColor = [UIColor whiteColor].CGColor;
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:NSStringFromSelector(@selector(strokeEnd))];
anim.delegate = self;
anim.fromValue = @0;
anim.toValue = @1;
anim.duration = 0.5;
[shaperLayer addAnimation:anim forKey:NSStringFromSelector(@selector(strokeEnd))];
[self.layer addSublayer:shaperLayer];
}
}
柱状图
//绘制柱状图
-(void)drawBarChart
{
UIBezierPath *path = [UIBezierPath bezierPath];
//绘制折线图
[path moveToPoint:_startPint];
[path addLineToPoint:_endPoint];
path.lineJoinStyle = kCGLineJoinRound;
//设置layer层
CAShapeLayer *shaperLayer = [CAShapeLayer layer];
shaperLayer.path = path.CGPath;
CGFloat scaleX = (self.frame.size.width - LEFT - RIGHT) / 8.0;
shaperLayer.lineWidth = scaleX;
shaperLayer.strokeColor = kPieRandColor.CGColor;
//shaperLayer.fillColor = kPieRandColor.CGColor;
//设置动画
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:NSStringFromSelector(@selector(strokeEnd))];
anim.delegate = self;
anim.fromValue = @0;
anim.toValue = @1;
anim.duration = 0.1;
[shaperLayer addAnimation:anim forKey:NSStringFromSelector(@selector(strokeEnd))];
[self.layer addSublayer:shaperLayer];
}
这里监听绘图动画结束,折线图以及柱状图实现绘制动画
#pragma mark CAAnimationDelegate 监听动画结束
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
if (_drawType == LineChart_Type) {
if (flag) {
[self drawAction];
}
}else if (_drawType == BarChart_Type){
if (flag) {
[self drawAction];
}
}
}
以上就是绘制图标的主要代码,希望对大家有帮助,如果大家有更好的思路或者更简洁的方法,希望大家多多指教。下面是源码连接
DEMO源码连接