1. 程式人生 > >iOS圖形繪製 UIBezierPath 繪製折線圖、柱狀圖、餅形圖

iOS圖形繪製 UIBezierPath 繪製折線圖、柱狀圖、餅形圖

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原始碼連線