iOS圖形繪製 UIBezierPath 繪製折線圖、柱狀圖、餅形圖
阿新 • • 發佈:2019-02-01
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原始碼連線