当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS 饼状图的封装与实现

iOS 饼状图的封装与实现

2018年09月17日  | 移动技术网移动技术  | 我要评论

有时候我们在处理一些数据的时候,需要用到柱状图,折线图和饼状图等来呈现数据,让用户能够对数据更加清晰明了化。下面我们来看一下简单的饼状图的实现。

延展

#import "nsobject+xusong.h"
**nsobject+xusong.h**
/**
 *  n秒后执行动作(不阻塞主线程)
 *
 *  @param seconds 几秒
 *  @param actions 几秒后执行的动作
 */
    - (void)dispatch_after_withseconds:(float)seconds actions:(void(^)(void))actions;

**nsobject+xusong.m**
- (void)dispatch_after_withseconds:(float)seconds actions:(void(^)(void))actions{
dispatch_after(dispatch_time(dispatch_time_now, (int64_t)(seconds * nsec_per_sec)), dispatch_get_main_queue(), ^{
    actions();
});

#import "nsstring+xusong.h"
**nsstring+xusong.h**
    /**
 *  计算字符串宽度(指当该字符串放在view时的自适应宽度)
 *
 *  @param size 填入预留的大小
 *  @param font 字体大小
 *
 *  @return 返回cgrect
 */
- (cgrect)stringwidthrectwithsize:(cgsize)size fontofsize:(cgfloat)font;

**nsstring+xusong.m**
- (cgrect)stringwidthrectwithsize:(cgsize)size fontofsize:(cgfloat)font{
nsdictionary * attributes = @{nsfontattributename: [uifont boldsystemfontofsize:font]};

return [self boundingrectwithsize:size options:nsstringdrawinguseslinefragmentorigin attributes:attributes context:nil];
}

#import "uicolor+xusong.h"
**uicolor+xusong.h**
@interface uicolor (xusong)
@property (nonatomic, assign, readonly) cgfloat red;
@property (nonatomic, assign, readonly) cgfloat green;
@property (nonatomic, assign, readonly) cgfloat blue;
@property (nonatomic, assign, readonly) cgfloat alpha;
@end

**uicolor+xusong.m**
@implementation uicolor (xusong)
- (nsdictionary *)getrgbdictionarybycolor{
    cgfloat r=0,g=0,b=0,a=0;
    if ([self respondstoselector:@selector(getred:green:blue:alpha:)]) {
        [self getred:&r green:&g blue:&b alpha:&a];
    }
    else {
        const cgfloat *components = cgcolorgetcomponents(self.cgcolor);
        r = components[0];
        g = components[1];
        b = components[2];
        a = components[3];
    }

    r = r * 255;
    g = g * 255;
    b = b * 255;

    return @{@"r":@(r),
             @"g":@(g),
             @"b":@(b),
             @"a":@(a)};
}

- (cgfloat)red{
    nsdictionary * dict = [self getrgbdictionarybycolor];
    return [dict[@"r"] floatvalue];
}

- (cgfloat)green{
    nsdictionary * dict = [self getrgbdictionarybycolor];
    return [dict[@"g"] floatvalue];
}

- (cgfloat)blue{
    nsdictionary * dict = [self getrgbdictionarybycolor];
    return [dict[@"b"] floatvalue];
}

- (cgfloat)alpha{
    nsdictionary * dict = [self getrgbdictionarybycolor];
    return [dict[@"a"] floatvalue];
}
@end

#import "uiview+xusong.h"
**uiview+xusong.h**
/**
 *  自定义边框
 *
 *  @param cornerradius 角落半径
 *  @param borderwidth  边框宽度
 *  @param color        边框颜色
 */
-(void)setbordercornerradius:(cgfloat)cornerradius andborderwidth:(cgfloat)borderwidth andbordercolor:(uicolor *)color;

**uiview+xusong.m**
-(void)setbordercornerradius:(cgfloat)cornerradius andborderwidth:(cgfloat)borderwidth andbordercolor:(uicolor *)color{
self.layer.cornerradius = cornerradius;
self.layer.borderwidth = borderwidth;
self.layer.bordercolor = color.cgcolor;
}

头文件

**zfchart.h**
#import "zfconst.h"
#import "zfpiechart.h"
#import "zfcolor.h"
**zfcolor.h**
#define zfblack [uicolor blackcolor]
#define zfdarkgray [uicolor darkgraycolor]
#define zflightgray [uicolor lightgraycolor]
#define zfwhite [uicolor whitecolor]
#define zfgray [uicolor graycolor]
#define zfred [uicolor redcolor]
#define zfgreen [uicolor greencolor]
#define zfblue [uicolor bluecolor]
#define zfcyan [uicolor cyancolor]
#define zfyellow [uicolor yellowcolor]
#define zfmagenta [uicolor magentacolor]
#define zforange [uicolor orangecolor]
#define zfpurple [uicolor purplecolor]
#define zfbrown [uicolor browncolor]
#define zfclear [uicolor clearcolor]
**zfconst.h**
#define screen_width [uiscreen mainscreen].bounds.size.width
#define screen_height [uiscreen mainscreen].bounds.size.height
#define adaptation_width7(width) [uiscreen mainscreen].bounds.size.width * (width) / 375
#define imgname(name) [uiimage imagenamed:name]
/**
 *  直接填写小数
 */
#define zfdecimalcolor(r, g, b, a) [uicolor colorwithred:r green:g blue:b alpha:a]

/**
 *  直接填写整数
 */
#define zfcolor(r, g, b, a) [uicolor colorwithred:r / 255.f green:g / 255.f blue:b / 255.f alpha:a]

/**
 *  随机颜色
 */
#define zfrandomcolor zfcolor(arc4random() % 256, arc4random() % 256, arc4random() % 256, 1)

#define navigationbar_height 64.f
#define tabbar_height 49.f

/**
 *  角度求三角函数sin值
 *  @param a 角度
 */
#define zfsin(a) sin(a / 180.f * m_pi)

/**
 *  角度求三角函数cos值
 *  @param a 角度
 */
#define zfcos(a) cos(a / 180.f * m_pi)

/**
 *  角度求三角函数tan值
 *  @param a 角度
 */
#define zftan(a) tan(a / 180.f * m_pi)

/**
 *  弧度转角度
 *  @param radian 弧度
 */
#define zfangle(radian) (radian / m_pi * 180.f)

/**
 *  角度转弧度
 *  @param angle 角度
 */
#define zfradian(angle) (angle / 180.f * m_pi)

/**
 *  坐标轴起点x值
 */
#define zfaxislinestartxpos 50.f

/**
 *  y轴label tag值
 */
#define ylinevaluelabeltag 100

/**
 *  x轴item宽度
 */
#define xlineitemwidth 25.f

/**
 *  x轴item间隔
 */
#define xlineitemgaplength 20.f


#warning message - 此属性最好不要随意修改
/**
 *  坐标y轴最大上限值到箭头的间隔距离 (此属性最好不要随意修改)
 */
#define zfaxislinegapfromylinemaxvaluetoarrow 20.f

画线和动画效果

#import “zftranslucencepath.h”

**zftranslucencepath.h**
    #import 
    #import 

    @interface zftranslucencepath : cashapelayer

    + (instancetype)layerwitharccenter:(cgpoint)center radius:(cgfloat)radius startangle:(cgfloat)startangle endangle:(cgfloat)endangle clockwise:(bool)clockwise;

    - (instancetype)initwitharccenter:(cgpoint)center radius:(cgfloat)radius startangle:(cgfloat)startangle endangle:(cgfloat)endangle clockwise:(bool)clockwise;
    @end

    **zftranslucencepath.m**
    @implementation zftranslucencepath

    + (instancetype)layerwitharccenter:(cgpoint)center radius:(cgfloat)radius startangle:(cgfloat)startangle endangle:(cgfloat)endangle clockwise:(bool)clockwise{
        return [[zftranslucencepath alloc] initwitharccenter:center radius:radius startangle:startangle endangle:endangle clockwise:clockwise];
    }

    - (instancetype)initwitharccenter:(cgpoint)center radius:(cgfloat)radius startangle:(cgfloat)startangle endangle:(cgfloat)endangle clockwise:(bool)clockwise{
        self = [super init];
        if (self) {
            self.fillcolor = nil;
            self.opacity = 0.5f;
            self.path = [self translucencepathwitharccenter:center radius:radius startangle:startangle endangle:endangle clockwise:clockwise].cgpath;
        }
        return self;
    }

    - (uibezierpath *)translucencepathwitharccenter:(cgpoint)center radius:(cgfloat)radius startangle:(cgfloat)startangle endangle:(cgfloat)endangle clockwise:(bool)clockwise{
        uibezierpath * bezierpath = [uibezierpath bezierpathwitharccenter:center radius:radius startangle:startangle endangle:endangle clockwise:clockwise];
        return bezierpath;
    }
    @end

主视图

#import “zfpiechart.h”

**zfpiechart.h**

#import 
typedef enum{
    /**
     *  保留2位小数形式(默认)
     */
    kpercenttypedecimal = 0,
    /**
     *  取整数形式(四舍五入)
     */
    kpercenttypeinteger = 1
}kpercenttype;

@interface zfpiechart : uiview

/** 标题 */
@property (nonatomic, copy) nsstring * title;
/** 数值数组 (存储的是nsstring类型) */
@property (nonatomic, strong) nsmutablearray * valuearray;
/** 名字数组 (存储的是nsstring类型) */
@property (nonatomic, strong) nsmutablearray * namearray;
/** 颜色数组 (存储的是uicolor类型) */
@property (nonatomic, strong) nsmutablearray * colorarray;
/** kpercenttype类型 */
@property (nonatomic, assign) kpercenttype percenttype;
/** 显示详细信息(默认为yes) */
@property (nonatomic, assign) bool isshowdetail;
/** 显示百分比(默认为yes) */
@property (nonatomic, assign) bool isshowpercent;

#pragma mark - public method

/**
 *  重绘
 */
- (void)strokepath;

@end

**zfpiechart.m**

#import "zfpiechart.h"
#import "zfconst.h"
#import "nsobject+xusong.h"
#import "nsstring+xusong.h"
#import "uicolor+xusong.h"
#import "uiview+xusong.h"
#import "zftranslucencepath.h"
#import "masonry.h"

#define percentlabeltag 100
#define detailbackgroundtag 500

@interface zfpiechart()

/** 总数 */
@property (nonatomic, assign) cgfloat totalvalue;
/** 半径 */
@property (nonatomic, assign) cgfloat radius;
/** 半径最大上限 */
@property (nonatomic, assign) cgfloat maxradius;
/** 记录每个圆弧开始的角度 */
@property (nonatomic, assign) cgfloat startangle;
/** 动画总时长 */
@property (nonatomic, assign) cftimeinterval totalduration;
/** 圆环线宽 */
@property (nonatomic, assign) cgfloat linewidth;
/** 记录valuearray当前元素的下标 */
@property (nonatomic, assign) nsinteger index;
/** 记录当前path的中心点 */
@property (nonatomic, assign) cgpoint centerpoint;
/** 半透明path延伸长度 */
@property (nonatomic, assign) cgfloat extendlength;
/** 记录圆环中心 */
@property (nonatomic, assign) cgpoint piecenter;
/** 记录初始高度 */
@property (nonatomic, assign) cgfloat originheight;
/** 存储每个圆弧动画开始的时间 */
@property (nonatomic, strong) nsmutablearray * starttimearray;
/** 记录每个path startangle 和 endangle, 数组里存的是nsdictionary */
@property (nonatomic, strong) nsmutablearray * angelarray;
/** 标题label */
@property (nonatomic, strong) uilabel * titlelabel;
/** 数值label */
@property (nonatomic, strong) uilabel * valuelabel;

@end

@implementation zfpiechart

- (nsmutablearray *)starttimearray{
    if (!_starttimearray) {
        _starttimearray = [nsmutablearray array];
    }
    return _starttimearray;
}

- (nsmutablearray *)angelarray{
    if (!_angelarray) {
        _angelarray = [nsmutablearray array];
    }
    return _angelarray;
}

/**
 *  初始化变量
 */
- (void)commoninit{
    _maxradius = self.frame.size.width > self.frame.size.height ? self.frame.size.height : self.frame.size.width;
    _radius = _maxradius * 0.27;
    _linewidth = _radius;
    _totalduration = 0.75f;
    _startangle = zfradian(-90);
    _extendlength = 10.f;
    _originheight = self.frame.size.height;
    _piecenter = cgpointmake(self.frame.size.width / 2, self.frame.size.height / 2);
    _isshowdetail = yes;
    _isshowpercent = yes;
}

- (instancetype)initwithframe:(cgrect)frame{
    self = [super initwithframe:frame];
    if (self) {
        [self commoninit];

        //数值label
        self.valuelabel = [[uilabel alloc] initwithframe:cgrectmake(0, 0, _radius/1.4, _radius/1.4)];
        self.valuelabel.font = [uifont boldsystemfontofsize:13.f];
        self.valuelabel.textalignment = nstextalignmentcenter;
        self.valuelabel.textcolor = [uicolor blackcolor];
        self.valuelabel.numberoflines = 0;
        self.valuelabel.center = self.piecenter;
        [self addsubview:self.valuelabel];
    }
    return self;
}

/**
 *  添加详情
 */
- (void)addui{
    cgfloat valuemoney = 0.0;
    for (nsinteger i = 0; i < self.valuearray.count; i++) {
        //装载容器
        uiview * background = [[uiview alloc] initwithframe:cgrectmake(0, self.frame.size.height + adaptation_height7(50) * i, self.frame.size.width, adaptation_height7(50))];
        background.tag = detailbackgroundtag + i;
        [self addsubview:background];

        uitapgesturerecognizer * tap = [[uitapgesturerecognizer alloc] initwithtarget:self action:@selector(showtranslucencepathaction:)];
        [background addgesturerecognizer:tap];

        //线条
        uiview *lineview = [[uiview alloc] init];
        lineview.backgroundcolor = [uicolor lightgraycolor];
        [background addsubview:lineview];
        [lineview mas_makeconstraints:^(masconstraintmaker *make) {
            make.top.equalto(background);
            make.left.equalto(background).offset(10);
            make.right.equalto(background);
            make.height.mas_offset(1);
        }];
        uiimageview *colorimage = [[uiimageview alloc] init];
        colorimage.image = imgname(_namearray[i]);
        [background addsubview:colorimage];
        [colorimage mas_makeconstraints:^(masconstraintmaker *make) {
            make.centery.equalto(background);
            make.left.equalto(background).offset(20);
            make.size.mas_equalto(cgsizemake(adaptation_width7(35), adaptation_width7(35)));
        }];

        //名称
        uilabel *namelabel = [[uilabel alloc] init];
        namelabel.text = _namearray[i];
        namelabel.font = [uifont boldsystemfontofsize:18];
        namelabel.textalignment = nstextalignmentleft;
        [background addsubview:namelabel];
        [namelabel mas_makeconstraints:^(masconstraintmaker *make) {
            make.centery.equalto(background);
            make.left.equalto(colorimage.mas_right).offset(15);
            make.size.mas_equalto(cgsizemake(60, 30));
        }];

        //数值
        uilabel *valuelabel = [[uilabel alloc] init];
        valuelabel.font = [uifont systemfontofsize:16];
        valuelabel.text = [nsstring stringwithformat:@"%@元",_valuearray[i]];
        valuelabel.textalignment = nstextalignmentcenter;
        [background addsubview:valuelabel];
        [valuelabel mas_makeconstraints:^(masconstraintmaker *make) {
            make.centerx.equalto(background);
            make.centery.equalto(background);
            make.size.mas_equalto(cgsizemake(150, 30));
        }];
        valuemoney += [_valuearray[i] floatvalue];
        self.valuelabel.text = [nsstring stringwithformat:@"总金额%.2f",valuemoney];
        //百分比
        uilabel *percentlabel = [[uilabel alloc] init];
        percentlabel.text = [self getpercent:i];
        percentlabel.font = [uifont systemfontofsize:16];
        percentlabel.textalignment = nstextalignmentright;
        [background addsubview:percentlabel];
        [percentlabel mas_makeconstraints:^(masconstraintmaker *make) {
            make.centery.equalto(background);
            make.right.equalto(background).offset(-15);
            make.size.mas_equalto(cgsizemake(80, 30));
        }];
    }

    //重设self.frame的值
    uilabel * lastlabel = (uilabel *)[self viewwithtag:detailbackgroundtag + self.valuearray.count - 1];
    self.frame = cgrectmake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, cgrectgetmaxy(lastlabel.frame) + 20);
}

#pragma mark - arc(圆弧)

/**
 *  填充
 *
 *  @return uibezierpath
 */
- (uibezierpath *)fill{
    //需要多少度的圆弧
    cgfloat angle = [self countangle:[_valuearray[_index] floatvalue]];

    uibezierpath * bezier = [uibezierpath bezierpathwitharccenter:_piecenter radius:_radius startangle:_startangle endangle:_startangle + angle clockwise:yes];
    self.centerpoint = [self getbezierpathcenterpointwithstartangle:_startangle endangle:_startangle + angle];
    //记录开始角度和结束角度
    nsdictionary * dict = @{@"startangle":@(_startangle), @"endangle":@(_startangle + angle)};
    [self.angelarray addobject:dict];

    _startangle += angle;

    return bezier;
}

/**
 *  cashapelayer
 *
 *  @return cashapelayer
 */
- (cashapelayer *)shapelayer{
    cashapelayer * layer = [cashapelayer layer];
    layer.fillcolor = nil;
    layer.strokecolor = [_colorarray[_index] cgcolor];
    layer.linewidth = _linewidth;
    layer.path = [self fill].cgpath;

    cabasicanimation * animation = [self animation];
    [layer addanimation:animation forkey:nil];

    return layer;
}

#pragma mark - 动画

/**
 *  填充动画过程
 *
 *  @return cabasicanimation
 */
- (cabasicanimation *)animation{
    cabasicanimation * fillanimation = [cabasicanimation animationwithkeypath:@"strokeend"];
    fillanimation.duration = [self countduration:_index];
    fillanimation.timingfunction = [camediatimingfunction functionwithname:kcamediatimingfunctionlinear];
    fillanimation.fillmode = kcafillmodeforwards;
    fillanimation.removedoncompletion = no;
    fillanimation.fromvalue = @(0.f);
    fillanimation.tovalue = @(1.f);

    return fillanimation;
}

#pragma mark - 清除控件

/**
 *  清除之前所有子控件
 */
- (void)removeallsublayers{
    [self.angelarray removeallobjects];
    self.frame = cgrectmake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, _originheight);

    nsarray * sublayers = [nsarray arraywitharray:self.layer.sublayers];
    for (calayer * layer in sublayers) {
        if (layer != self.titlelabel.layer && layer != self.valuelabel.layer) {
            [layer removeallanimations];
            [layer removefromsuperlayer];
        }
    }

    for (uiview * view in self.subviews) {
        if (view != self.titlelabel && view != self.valuelabel) {
            [view removefromsuperview];
        }
    }
}

/**
 *  移除半透明path
 */
- (void)removezftranslucencepath{
    nsmutablearray * sublayers = [nsmutablearray arraywitharray:self.layer.sublayers];
    for (calayer * layer in sublayers) {
        if ([layer iskindofclass:[zftranslucencepath class]]) {
            [layer removefromsuperlayer];
        }
    }
}

#pragma mark - 半透明path

/**
 *  半透明path
 *
 *  @param startangle 开始角度
 *  @param endangle   结束角度
 *  @param index      下标
 *
 *  @return zftranslucencepath
 */
- (zftranslucencepath *)translucencepathshapelayerwithstartangle:(cgfloat)startangle endangle:(cgfloat)endangle index:(nsinteger)index{
    zftranslucencepath * layer = [zftranslucencepath layerwitharccenter:_piecenter radius:_radius + _extendlength startangle:startangle endangle:endangle clockwise:yes];
    layer.strokecolor = [_colorarray[index] cgcolor];
    layer.linewidth = _linewidth + _extendlength;
    return layer;
}

#pragma mark - public method

/**
 *  重绘
 */
- (void)strokepath{
    self.userinteractionenabled = no;
    [self removeallsublayers];
    _startangle = zfradian(-90);

    for (nsinteger i = 0; i < _valuearray.count; i++) {
        [self dispatch_after_withseconds:[self.starttimearray[i] floatvalue] actions:^{
            _index = i;
            cashapelayer * shapelayer = [self shapelayer];
            [self.layer addsublayer:shapelayer];
            _isshowpercent == yes?[self creatpercentlabel]:nil;
        }];
    }

    [self dispatch_after_withseconds:_totalduration actions:^{
        self.userinteractionenabled = yes;
    }];

    _isshowdetail == yes?[self addui]:nil;
}

#pragma mark - uiresponder

- (void)touchesbegan:(nsset *)touches withevent:(uievent *)event{
    [super touchesbegan:touches withevent:event];
    uitouch * touch = [touches anyobject];
    cgpoint point = [touch locationinview:self];
    if (point.y > _originheight / 8.f * 7 + 30) {
        return;
    }

    //求弧度
    cgfloat x = (point.x - _piecenter.x);
    cgfloat y = (point.y - _piecenter.y);
    cgfloat radian = atan2(y, x);
    //当超过180度时,要加2π
    if (y < 0 && x < 0) {
        radian = radian + zfradian(360);
    }

    //判断点击位置的角度在哪个path范围上
    for (nsinteger i = 0; i < self.angelarray.count; i++) {
        nsdictionary * dict = self.angelarray[i];
        cgfloat startangle = [dict[@"startangle"] floatvalue];
        cgfloat endangle = [dict[@"endangle"] floatvalue];

        if (radian >= startangle && radian < endangle) {
            [self removezftranslucencepath];
            [self.layer addsublayer:[self translucencepathshapelayerwithstartangle:startangle endangle:endangle index:i]];
            uilabel * percentlabel = [self viewwithtag:percentlabeltag + i];
            [self bringsubviewtofront:percentlabel];
            self.valuelabel.text = _valuearray[i];

            return;
        }
    }
}

/**
 *  显示半透明path action
 *
 *  @param sender uitapgesturerecognizer
 */
- (void)showtranslucencepathaction:(uitapgesturerecognizer *)sender{
    nsinteger index = sender.view.tag - detailbackgroundtag;
    nsdictionary * dict = self.angelarray[index];
    cgfloat startangle = [dict[@"startangle"] floatvalue];
    cgfloat endangle = [dict[@"endangle"] floatvalue];

    [self removezftranslucencepath];
    [self.layer addsublayer:[self translucencepathshapelayerwithstartangle:startangle endangle:endangle index:index]];
    uilabel * percentlabel = [self viewwithtag:percentlabeltag + index];
    [self bringsubviewtofront:percentlabel];
    self.valuelabel.text = _valuearray[index];
}

#pragma mark - 获取每个item所占百分比

/**
 *  计算每个item所占角度大小
 *
 *  @param value 每个item的value
 *
 *  @return 返回角度大小
 */
- (cgfloat)countangle:(cgfloat)value{
    //计算百分比
    cgfloat percent = value / _totalvalue;
    //需要多少度的圆弧
    cgfloat angle = m_pi * 2 * percent;
    return angle;
}

#pragma mark - 计算每个圆弧执行动画持续时间

/**
 *  计算每个圆弧执行动画持续时间
 *
 *  @param index 下标
 *
 *  @return cftimeinterval
 */
- (cftimeinterval)countduration:(nsinteger)index{
    if (_totalduration < 0.1f) {
        _totalduration = 0.1f;
    }
    float count = _totalduration / 0.1f;
    cgfloat averageangle =  m_pi * 2 / count;
    cgfloat time = [self countangle:[_valuearray[index] floatvalue]] / averageangle * 0.1;

    return time;
}

#pragma mark - 获取每个path的中心点

/**
 *  获取每个path的中心点
 *
 *  @return cgfloat
 */
- (cgpoint)getbezierpathcenterpointwithstartangle:(cgfloat)startangle endangle:(cgfloat)endangle{
    //一半角度(弧度)
    cgfloat halfangle = (endangle - startangle) / 2;
    //中心角度(弧度)
    cgfloat centerangle = halfangle + startangle;
    //中心角度(角度)
    cgfloat realangle = zfangle(centerangle);

    cgfloat center_xpos = zfcos(realangle) * _radius + _piecenter.x;
    cgfloat center_ypos = zfsin(realangle) * _radius + _piecenter.y;

    return cgpointmake(center_xpos, center_ypos);
}

#pragma mark - 添加百分比label

/**
 *  添加百分比label
 */
- (void)creatpercentlabel{
    nsstring * string = [self getpercent:_index];
    cgrect rect = [string stringwidthrectwithsize:cgsizemake(0, 0) fontofsize:9.f];

    uilabel * label = [[uilabel alloc] initwithframe:cgrectmake(0, 0, rect.size.width, rect.size.height)];
    if ([string isequaltostring:@"0.00%"]) {
        label.text = @"";
    }else {
        label.text = string;
    }
    label.alpha = 0.f;
    label.textalignment = nstextalignmentcenter;
    label.font = [uifont boldsystemfontofsize:9.f];
    label.center = self.centerpoint;
    label.tag = percentlabeltag + _index;
    [self addsubview:label];

    [uiview animatewithduration:[self countduration:_index] animations:^{
        label.alpha = 1.f;
    }];

    //获取r,g,b三色值
    cgfloat red = [_colorarray[_index] red];
    cgfloat green = [_colorarray[_index] green];
    //path颜色为深色时,更改文字颜色
    if ((red < 180.f && green < 180.f)) {
        label.textcolor = [uicolor whitecolor];
    }
}

/**
 *  计算百分比
 *
 *  @return nsstring
 */
- (nsstring *)getpercent:(nsinteger)index{
    cgfloat percent = [_valuearray[index] floatvalue] / _totalvalue * 100;
    nsstring * string;
    if (self.percenttype == kpercenttypedecimal) {
        string = [nsstring stringwithformat:@"%.2f%%",percent];
    }else if (self.percenttype == kpercenttypeinteger){
        string = [nsstring stringwithformat:@"%d%%",(int)roundf(percent)];
    }
    return string;
}

#pragma mark - 重写setter,getter方法

- (void)setvaluearray:(nsmutablearray *)valuearray{
    _valuearray = valuearray;
    _totalvalue = 0;
    [self.starttimearray removeallobjects];
    cftimeinterval starttime = 0.f;
    //计算总数
    for (nsinteger i = 0; i < valuearray.count; i++) {
        _totalvalue += [valuearray[i] floatvalue];
    }

    //计算每个path的开始时间
    for (nsinteger i = 0; i < valuearray.count; i++) {
        [self.starttimearray addobject:[nsnumber numberwithdouble:starttime]];
        cftimeinterval duration = [self countduration:i];
        starttime += duration;
    }
}

@end

饼状图效果

#import “viewcontroller.h”

**#import "viewcontroller.h"**
#import 
@interface viewcontroller : uiviewcontroller

@end

**#import "viewcontroller.m"**

#import "viewcontroller.h"
#import "zfchart.h"

@interface viewcontroller ()

@end

@implementation viewcontroller

- (void)viewdidload {
    [super viewdidload];
    zfpiechart *piechart = [[zfpiechart alloc] initwithframe:cgrectmake(0, 0, screen_width, screen_width)];
    piechart.valuearray = [nsmutablearray arraywitharray:@"410", @"510", @"380", @"420", @"260",nil];
piechart.namearray = [nsmutablearray arraywithobjects:@"购物", @"美食", @"住房", @"交通", @"娱乐", nil];
piechart.colorarray = [nsmutablearray arraywithobjects:zfcolor(253, 118, 152, 1), zfcolor(254, 223, 219, 1), zfcolor(254, 206, 103, 1), zfcolor(81, 146, 218, 1), zfcolor(112, 182, 146, 1), nil];
[self.view addsubview:piechart];
[self.piechart strokepath];

}


- (void)didreceivememorywarning {
    [super didreceivememorywarning];
    // dispose of any resources that can be recreated.
}


@end

效果图

这里写图片描述
这里写图片描述

饼状图效果图。本文的demo是借鉴自网上,非博主纯原创。敬请谅解。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网