iOS 饼图的实现封装

效果图:


主要代码:

PieChart.h

#import <UIKit/UIKit.h>

@interface PieChart : UIView
@property(nonatomic,strong)NSArray *percentages;//占比数组
@property(nonatomic,strong)NSArray *colors;//占比的颜色数组
@property(nonatomic,strong)NSArray *texts;//文本数组
@property(nonatomic,strong)UIFont *textFont;//文本字体大小
@property(nonatomic,strong)UIColor *textColor;//文本字体颜色
@property(nonatomic)CGFloat textWidth;
@property(nonatomic)CGFloat textHeight;

@end

PieChart.m

#import "PieChart.h"
#define CENTER_X self.bounds.size.width / 2
#define CENTER_Y self.bounds.size.height / 2

#define FIRST_LINE_X(x) CENTER_X + x
#define FIRST_LINE_Y(y) CENTER_Y + y

#define SEC_LINE_X(x) x > 0 ? FIRST_LINE_X(x) + secLine : FIRST_LINE_X(x) - secLine

#define SIN(x) sin(x / 180 * M_PI)
#define COS(x) cos(x / 180 * M_PI)

static NSInteger secLine = 10;//第二条线的长度
static NSInteger firstLine = 5;//第一条线的长度
static CGFloat radiusRatio = 4.5;//半径比率

@interface PieChart (){
    NSInteger totalAngle;
    CGFloat radius;
}

@end
@implementation PieChart
- (void)awakeFromNib {
    [super awakeFromNib];
    [self commonInit];
}

-(instancetype)init {
    if (self = [super init]) {
        [self commonInit];
    }
    return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        [self commonInit];
    }
    return self;
}
-(instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self commonInit];
    }
    return self;
}

-(void)commonInit{
    self.textColor = [UIColor blackColor];
    self.textFont = [UIFont systemFontOfSize:6];
    self.textWidth = 30;
    self.textHeight = 30;
}

- (void)drawRect:(CGRect)rect {
    for (UIView *view in self.subviews) {
        [view removeFromSuperview];
    }
    CGFloat width = rect.size.width;
    CGFloat height = rect.size.height;
    
    if (width > height) {
        radius = height/radiusRatio;
    }else {
        radius = width/radiusRatio;
    }
    CGPoint center = CGPointMake(width/2, height/2);
    
    CGFloat all;
    //已加载的扇形弧度总和
    CGFloat endPercent = 0.0;
    //当前扇形所占弧度
    CGFloat curPercent = 0.0;
    //每个扇形的百分比
    CGFloat perPercent = 0.0;

    for (NSNumber *n in self.percentages) {
        all += [n floatValue];
    }
    
    for (int i = 0; i<self.percentages.count; i++) {
        perPercent = [self.percentages[i] floatValue] / all;
        curPercent = perPercent * 2 * M_PI;
        endPercent = perPercent * 2 * M_PI + endPercent;

        [(UIColor *)self.colors[i] set];
        UIBezierPath *path = [UIBezierPath new];
        [path moveToPoint:center];
        [path addArcWithCenter:center radius:radius startAngle:endPercent - curPercent  endAngle:endPercent clockwise:YES];
        [path fill];
        [path closePath];
        
        double angle = [self countLocationOftheExplainLine:endPercent curDegrees:curPercent];
        [self drawLineAngle:angle i:i];
    }
}

-(double)countLocationOftheExplainLine:(CGFloat)totalDegrees curDegrees:(CGFloat)curDegrees {
    CGFloat percent = (totalDegrees - curDegrees / 2) / M_PI_2;
    //和横纵轴形成的夹角
    totalAngle = percent * 90;
    //判断所在范围
    if ((totalAngle >= 90 && totalAngle < 180) || (totalAngle >= 270 && totalAngle < 360)) {
        return 90 - totalAngle % 90;
    }
    return totalAngle % 90 ;
}

//画线
- (void)drawLineAngle:(double)angle i:(int)i{
    CGFloat pointX = COS(angle);
    CGFloat pointY = SIN(angle);
    if (totalAngle >= 90 && totalAngle < 180) {
        pointX = -pointX;
    }
    if (totalAngle >= 180 && totalAngle < 270) {
        pointX = -pointX;
        pointY = -pointY;
    }
    if (totalAngle >= 270 && totalAngle < 360) {
        pointY = -pointY;
    }
    
    CGFloat lineX = FIRST_LINE_X(pointX * (radius + firstLine));
    CGFloat lineY = FIRST_LINE_Y(pointY * (radius + firstLine));
    
    [(UIColor *)self.colors[i] set];

    UIBezierPath *linePath = [UIBezierPath new];
    
    [linePath moveToPoint:CGPointMake(FIRST_LINE_X(pointX * radius/2), FIRST_LINE_Y(pointY * radius/2))];
    [linePath addLineToPoint:CGPointMake(lineX, lineY)];
    [linePath addLineToPoint:CGPointMake(SEC_LINE_X(pointX*(radius + firstLine)), lineY)];
    [linePath stroke];
    [linePath closePath];
    
    [self addLabelPointX:lineX pointY:lineY i:i];
}  

//添加文本
- (void)addLabelPointX:(CGFloat)pointX pointY:(CGFloat)pointY i:(int)i{
    if (pointX < CENTER_X) {
        pointX -= self.textHeight + secLine;
    }else {
        pointX += secLine;
    }
    UILabel *percentLabel = [[UILabel alloc]initWithFrame:CGRectMake(pointX, pointY - self.textHeight/2, self.textWidth , self.textHeight)];
    percentLabel.text = [NSString stringWithFormat:@"%@",self.texts[i]];
    percentLabel.textAlignment = NSTextAlignmentLeft;
    percentLabel.numberOfLines = 0;
    if (pointX < CENTER_X) {
        percentLabel.textAlignment = NSTextAlignmentRight;
    }
    percentLabel.textColor = self.textColor;
    percentLabel.font = self.textFont;
    [self addSubview:percentLabel];
}

@end


使用:



    self.pieChart.percentages = @[@20,@3,@59,@19,@100,@59,@15];
    self.pieChart.colors = @[[UIColor greenColor],[UIColor redColor],[UIColor yellowColor],[UIColor blueColor],[UIColor lightGrayColor],[UIColor greenColor],[UIColor redColor]];
    NSArray *arr =  @[@"优",@"良",@"轻度污染",@"中度污染",@"重度污染",@"严重污染",@"—"];
    NSMutableArray *marr = [NSMutableArray array];
    int index = 0;
    for (NSNumber *n in self.pieChart.percentages) {
        [marr addObject:[NSString stringWithFormat:@"%@:%@%%",arr[index],n]];
        index++;
    }
    
    self.pieChart.texts = marr;
    [self.pieChart setNeedsDisplay];


我的业余技术微信公众号:YKJGZH,欢迎大家进入



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值