iOS開發(fā)之自定義一個(gè)數(shù)據(jù)漏斗圖

前言:
百度ECharts上有很多漂亮的圖表,但是對(duì)于native應(yīng)用并不太友好督赤,今天記錄一下用OC自定義一個(gè)漏斗圖嘁灯,實(shí)現(xiàn)數(shù)據(jù)動(dòng)態(tài)加載,圖表實(shí)時(shí)更新够挂。

思路:
1.將漏斗圖橫向切割旁仿,假如有四組數(shù)據(jù)藕夫,就橫向切割為四等分孽糖,每一個(gè)部分將由一個(gè)UIButton來實(shí)現(xiàn)枯冈,實(shí)際上就是將四個(gè)UIButton疊起來(本文記錄的是四組數(shù)據(jù),所以就以四組數(shù)據(jù)為例)办悟;
2.通過給定數(shù)據(jù)尘奏,計(jì)算每一個(gè)UIButton對(duì)應(yīng)的四個(gè)點(diǎn),重寫UIButton的drawRect方法病蛉,利用UIBezierPath+CAShapeLayer繪制每個(gè)UIButton的實(shí)際大小跟形狀炫加;
3.利用CABasicAnimation添加一個(gè)繪制動(dòng)畫;
4.添加一個(gè)點(diǎn)擊響應(yīng)來顯示每一組數(shù)據(jù)铺然;

整體預(yù)覽
如下圖所示俗孝,每一個(gè)四邊形(最后一個(gè)是三角形)都是根據(jù)給定數(shù)據(jù)動(dòng)態(tài)繪制出來的:

funnel.gif

實(shí)現(xiàn)步驟
1.首先重寫UIButton的drawRect方法,實(shí)現(xiàn)一個(gè)根據(jù)給定四個(gè)點(diǎn)動(dòng)態(tài)創(chuàng)建一個(gè)UIButton:
.h文件添加一個(gè)pointArray

#import <UIKit/UIKit.h>


NS_ASSUME_NONNULL_BEGIN

@interface FHXCustomButton : UIButton

@property (nonatomic, strong) NSMutableArray *pointArray;

@end

NS_ASSUME_NONNULL_END

.m文件實(shí)現(xiàn)重寫drawRect

#import "FHXCustomButton.h"


@interface FHXCustomButton()

@property (nonatomic, strong) UIBezierPath * path;

@end
@implementation FHXCustomButton

// pointArray
- (void)setPointArray:(NSMutableArray *)pointArray
{
    _pointArray = pointArray;
}

// 繪制圖形時(shí)添加path遮罩
- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];
    
    CAShapeLayer *shapLayer = [CAShapeLayer layer];
    shapLayer.fillColor = [UIColor redColor].CGColor;
    self.layer.mask = shapLayer;
    
    //獲取四個(gè)點(diǎn)
    CGPoint point0 = CGPointFromString(_pointArray[0]);
    CGPoint point1 = CGPointFromString(_pointArray[1]);
    CGPoint point2 = CGPointFromString(_pointArray[2]);
    CGPoint point3 = CGPointFromString(_pointArray[3]);
    
    //構(gòu)造fromPath
    UIBezierPath * fromPath = [UIBezierPath bezierPath];
    [fromPath moveToPoint:point0];
    [fromPath addLineToPoint:point0];//起始的path也必須是一個(gè)矩形魄健,不然動(dòng)畫效果會(huì)有區(qū)別
    [fromPath addLineToPoint:point1];
    [fromPath addLineToPoint:point1];//同上
    shapLayer.path = fromPath.CGPath;
    
    //構(gòu)造toPath(最終圖形樣式)
    UIBezierPath * toPath = [UIBezierPath bezierPath];
    [toPath moveToPoint:point0];
    [toPath addLineToPoint:point3];
    [toPath addLineToPoint:point2];
    [toPath addLineToPoint:point1];
    [toPath closePath];
    
    // 構(gòu)造動(dòng)畫
    CABasicAnimation * animation = [CABasicAnimation animation];
    animation.keyPath = @"path";
    animation.duration = 1;
    animation.fromValue = (id)fromPath.CGPath;
    shapLayer.path = (__bridge CGPathRef _Nullable)((id)toPath.CGPath);
    [shapLayer addAnimation:animation forKey:nil];
}
// 點(diǎn)擊的覆蓋方法赋铝,點(diǎn)擊時(shí)判斷點(diǎn)是否在path內(nèi),YES則響應(yīng)沽瘦,NO則不響應(yīng)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    BOOL res = [super pointInside:point withEvent:event];
    if (res)
    {
        if ([self.path containsPoint:point])
        {
            return YES;
        }
        return NO;
    }
    return NO;
}
@end

動(dòng)態(tài)繪制UIButton效果如下圖:


customButton.gif

本文是以四組數(shù)據(jù)為例革骨,所以只需要?jiǎng)?chuàng)建四個(gè)上述button,即可實(shí)現(xiàn)一個(gè)數(shù)據(jù)漏斗圖析恋。

2.利用上述customButton良哲,實(shí)現(xiàn)一個(gè)數(shù)據(jù)漏斗圖,新建一個(gè)view繼承UIView:
.文件

#import <UIKit/UIKit.h>
#import "FHXCustomButton.h"
#import "FHXFunnelModel.h"
#import "FHXChartNoDataView.h"

#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
#define kViewWidth(View) CGRectGetWidth(View.frame)
#define kViewHeight(View) CGRectGetHeight(View.frame)
#define kMidHeight 3.0f

NS_ASSUME_NONNULL_BEGIN

@interface FHXFunnelView : UIView

/*標(biāo)題*/
@property(nonatomic,strong)NSString * title;
/*小標(biāo)題*/
@property(nonatomic,strong)NSMutableArray * desArray;
/*數(shù)據(jù)*/
@property(nonatomic,strong)FHXFunnelModel * funnelModel;

/*點(diǎn)擊展示文案*/
@property(nonatomic,strong)UIButton * showButton;
/*無數(shù)據(jù)*/
@property(nonatomic,strong)FHXChartNoDataView * noDataView;
@end

NS_ASSUME_NONNULL_END

.m文件里創(chuàng)建四個(gè)FHXCustomButton助隧,從上到下一次排開筑凫,并在y軸(數(shù)值方向)對(duì)齊,通過傳入的四組數(shù)據(jù)計(jì)算每一個(gè)button的位置并村,這里是將四個(gè)button的高度固定為60漏健,第一個(gè)button的上邊寬固定,下邊寬由前兩個(gè)數(shù)據(jù)的比例來計(jì)算(類似于一個(gè)等腰梯形)橘霎,依次類推蔫浆,最后一Button將會(huì)被繪制成一個(gè)等腰三角形,具體實(shí)現(xiàn)代碼如下

#import "FHXFunnelView.h"
#import "Masonry.h"
#import "UIColor+Extensions.h"
#import "UIButton+HXEnlargeTouchArea.h"
@implementation FHXFunnelView{
    FHXCustomButton * firstBtn;
    FHXCustomButton * secondBtn;
    FHXCustomButton * thirdBtn;
    FHXCustomButton * fourthBtn;
    UILabel * titleLabel;
    CGFloat registerCount;
    CGFloat openCount;
    CGFloat lendCount;
    CGFloat repeatCount;
    NSMutableArray * labelArray;
    NSMutableArray * imageViewArray;
}
//添加漏斗數(shù)據(jù)
-(void)setFunnelModel:(FHXFunnelModel *)funnelModel{   
    //刷新數(shù)據(jù)隱藏顯示button
    self.showButton.hidden = YES;
    if (funnelModel == nil) {
        //暫無數(shù)據(jù)
        self.noDataView.hidden = NO;
        return;
    }else{
        self.noDataView.hidden = YES;
    }
    _funnelModel = funnelModel;
    //數(shù)據(jù)整化
    registerCount = _funnelModel.firstItemNum.floatValue;
    openCount = _funnelModel.secondItemNum.floatValue;
    lendCount = _funnelModel.thirdItemNum.floatValue;
    repeatCount = _funnelModel.fourthItemNum.floatValue;
    
    //處理數(shù)據(jù)為0的情況
    if (registerCount == 0) {
        //暫無數(shù)據(jù)
        self.noDataView.hidden = NO;
        return;
    }else{
        self.noDataView.hidden = YES;
    }
    
    if (openCount == 0) {
        openCount = 1;
        lendCount = 1;
        repeatCount = 1;
    }
    if (lendCount == 0) {
        lendCount = 1;
        repeatCount = 1;
    }
    if (repeatCount == 0) {
        repeatCount = 1;
    }
    
    //注冊
    firstBtn.frame = CGRectMake(32, 62, SCREEN_WIDTH - 32*2, 60);
    CGFloat baseProportion1 = openCount/registerCount;
    CGFloat leftProportion1 = (1 - baseProportion1)/2.0f;
    CGFloat rightProportion1 = 1 - leftProportion1;
    // 添加路徑關(guān)鍵點(diǎn)array
    NSMutableArray *pointArray = [NSMutableArray array];
    [pointArray addObject:NSStringFromCGPoint(CGPointMake(0.f, 0.f))];
    [pointArray addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(firstBtn), 0.f))];
    [pointArray addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(firstBtn) *rightProportion1, firstBtn.frame.size.height))];
    [pointArray addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(firstBtn) *leftProportion1, kViewHeight(firstBtn)))];
    firstBtn.pointArray = [pointArray mutableCopy];
    firstBtn.backgroundColor = [UIColor colorWithHex:0x4162ff];
    [firstBtn setNeedsDisplay];
    
    //開戶
    secondBtn.frame = CGRectMake(32, 62 + 60, kViewWidth(firstBtn) *baseProportion1, 60);
    [secondBtn mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(firstBtn.mas_bottom).with.offset(kMidHeight);
        make.centerX.equalTo(firstBtn);
        make.width.equalTo(@(kViewWidth(firstBtn) * baseProportion1));
        make.height.equalTo(@60.f);
    }];
    CGFloat baseProportion2 = lendCount/openCount;
    CGFloat leftProportion2 = (1 - baseProportion2)/2.0f;
    CGFloat rightProportion2 = 1 - leftProportion2;
    // 添加路徑關(guān)鍵點(diǎn)array
    NSMutableArray *pointArray1 = [NSMutableArray array];
    [pointArray1 addObject:NSStringFromCGPoint(CGPointMake(0.f, 0.f))];
    [pointArray1 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(secondBtn), 0.f))];
    [pointArray1 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(secondBtn) *rightProportion2, secondBtn.frame.size.height))];
    [pointArray1 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(secondBtn) *leftProportion2, kViewHeight(secondBtn)))];
    secondBtn.pointArray = [pointArray1 mutableCopy];
    secondBtn.backgroundColor = [UIColor colorWithHex:0xffce66];
    [secondBtn setNeedsDisplay];
    
    //綁卡
    thirdBtn.frame = CGRectMake(32, 62 + 60, kViewWidth(secondBtn) * baseProportion2, 60);
    [thirdBtn mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(secondBtn.mas_bottom).with.offset(kMidHeight);
        make.centerX.equalTo(secondBtn);
        make.width.equalTo(@(kViewWidth(secondBtn) * baseProportion2));
        make.height.equalTo(@60.f);
    }];
    
    CGFloat baseProportion3 = repeatCount/lendCount;
    CGFloat leftProportion3 = (1 - baseProportion3)/2.0f;
    CGFloat rightProportion3 = 1 - leftProportion3;
    // 添加路徑關(guān)鍵點(diǎn)array
    NSMutableArray *pointArray2 = [NSMutableArray array];
    [pointArray2 addObject:NSStringFromCGPoint(CGPointMake(0.f, 0.f))];
    [pointArray2 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(thirdBtn), 0.f))];
    [pointArray2 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(thirdBtn) *rightProportion3, thirdBtn.frame.size.height))];
    [pointArray2 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(thirdBtn) *leftProportion3, kViewHeight(thirdBtn)))];
    thirdBtn.pointArray = [pointArray2 mutableCopy];
    thirdBtn.backgroundColor = [UIColor colorWithHex:0xff6f6f];
    [thirdBtn setNeedsDisplay];
    
    //下單
    fourthBtn.frame = CGRectMake(32, 62 + 60, kViewWidth(thirdBtn) * baseProportion3, 60);
    [fourthBtn mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(thirdBtn.mas_bottom).with.offset(kMidHeight);
        make.centerX.equalTo(thirdBtn);
        make.width.equalTo(@(kViewWidth(thirdBtn) * baseProportion3));
        make.height.equalTo(@60.f);
    }];
    
    // 添加路徑關(guān)鍵點(diǎn)array
    NSMutableArray *pointArray3 = [NSMutableArray array];
    [pointArray3 addObject:NSStringFromCGPoint(CGPointMake(0.f, 0.f))];
    [pointArray3 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(fourthBtn), 0.f))];
    [pointArray3 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(fourthBtn) *1/2, fourthBtn.frame.size.height))];
    [pointArray3 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(fourthBtn) *1/2, kViewHeight(fourthBtn)))];
    fourthBtn.pointArray = [pointArray3 mutableCopy];
    fourthBtn.backgroundColor = [UIColor colorWithHex:0x8ea3ff];
    [fourthBtn setNeedsDisplay];
    
    //擴(kuò)大button點(diǎn)擊區(qū)域
    [firstBtn setTouchExpandEdgeWithTop:0 right:40 bottom:0 left:40];
    [secondBtn setTouchExpandEdgeWithTop:0 right:40 bottom:0 left:40];
    [thirdBtn setTouchExpandEdgeWithTop:0 right:40 bottom:0 left:40];
    [fourthBtn setTouchExpandEdgeWithTop:0 right:40 bottom:0 left:40];
}
//大標(biāo)題
-(void)setTitle:(NSString *)title{
    _title = title;
    titleLabel.text = _title;
}
//小標(biāo)題
-(void)setDesArray:(NSMutableArray *)desArray{
    _desArray = desArray;
    for (int i = 0; i < _desArray.count; i++) {
        //文字
        UILabel * label = labelArray[i];
        label.text = _desArray[i];
        //標(biāo)識(shí)
        UIImageView * imageView = imageViewArray[i];
        if (i == 0) {
            [label mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.left.mas_equalTo(self).offset(32);
                make.bottom.mas_equalTo(self).offset(-15);
                make.width.equalTo(@25.0f);
                make.height.equalTo(@15.0f);
            }];
            
            [imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.left.equalTo(label);
                make.top.mas_equalTo(label.mas_bottom).offset(5);
                make.width.equalTo(@25.0f);
                make.height.equalTo(@5.0f);
            }];
        }else{
            
            UILabel * preLabel = labelArray[i - 1];
            [label mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.left.mas_equalTo(preLabel.mas_right).offset(14);
                make.centerY.equalTo(preLabel);
                make.width.equalTo(@25.0f);
                make.height.equalTo(@15.0f);
            }];
            
            [imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.left.equalTo(label);
                make.top.mas_equalTo(label.mas_bottom).offset(5);
                make.width.equalTo(@25.0f);
                make.height.equalTo(@5.0f);
            }];
        }       
    }
}
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        //標(biāo)題
        titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, frame.size.width, 40)];
        titleLabel.textAlignment = NSTextAlignmentCenter;
        titleLabel.font = [UIFont boldSystemFontOfSize:18];
        [self addSubview:titleLabel];
        
        //注冊
        firstBtn = [FHXCustomButton buttonWithType:UIButtonTypeCustom];
        firstBtn.frame = CGRectMake(32, 62, SCREEN_WIDTH - 32*2, 60);
        firstBtn.layer.masksToBounds = YES;
        firstBtn.layer.cornerRadius = 5.0f;
        firstBtn.tag = 5001;
        [firstBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:firstBtn];

        //開戶
        secondBtn = [FHXCustomButton buttonWithType:UIButtonTypeCustom];
        [self addSubview:secondBtn];
        secondBtn.tag = 5002;
        [secondBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];

        //綁卡
        thirdBtn = [FHXCustomButton buttonWithType:UIButtonTypeCustom];
        thirdBtn.frame = fourthBtn.frame;
        [self addSubview:thirdBtn];
        thirdBtn.tag = 5003;
        [thirdBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
        
        //下單
        fourthBtn = [FHXCustomButton buttonWithType:UIButtonTypeCustom];
        [self addSubview:fourthBtn];
        fourthBtn.tag = 5004;
        [fourthBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
        
        //創(chuàng)建四個(gè)標(biāo)識(shí)標(biāo)簽
        labelArray = [[NSMutableArray alloc]initWithCapacity:0];
        imageViewArray = [[NSMutableArray alloc]initWithCapacity:0];
        for (int i = 0; i < 4; i++) {
            UILabel * testLabel = [[UILabel alloc]init];
            testLabel.textColor = [UIColor colorWithHex:0x333333];
            testLabel.font = [UIFont systemFontOfSize:12];
            testLabel.textAlignment = NSTextAlignmentCenter;
            [labelArray addObject:testLabel];
            [self addSubview:testLabel];
            
            UIImageView * imageVIew = [[UIImageView alloc]init];
            imageVIew.layer.masksToBounds = YES;
            imageVIew.layer.cornerRadius = 2.5f;
            [imageViewArray addObject:imageVIew];
            [self addSubview:imageVIew];
            switch (i) {
                case 0:
                    imageVIew.backgroundColor = [UIColor colorWithHex:0x4262ff];
                    break;
                case 1:
                    imageVIew.backgroundColor = [UIColor colorWithHex:0xFFCE66];
                    break;
                case 2:
                    imageVIew.backgroundColor = [UIColor colorWithHex:0xFF6F6F];
                    break;
                case 3:
                    imageVIew.backgroundColor = [UIColor colorWithHex:0x8EA3FF];
                    break;
                default:
                    break;
            }
        }
    }
    return self;
}
//點(diǎn)擊效果
-(void)btnAction:(id)sender{
    self.showButton.hidden = NO;
    UIButton * btn = (UIButton *)sender;
    if (btn.tag == 5001) {
        [self.showButton mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(100 - firstBtn.center.x);
            make.centerY.equalTo(firstBtn);
            make.width.equalTo(@117.0f);
            make.height.equalTo(@43.0f);
        }];
        
        [self.showButton setBackgroundImage:[UIImage imageNamed:@"icon_message_register"] forState:UIControlStateNormal];
        [self.showButton setTitle:[NSString stringWithFormat:@"人數(shù): %.0f",registerCount] forState:UIControlStateNormal];
    }
    if (btn.tag == 5002) {
        [self.showButton mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(100 - secondBtn.center.x);
            make.centerY.equalTo(secondBtn);
            make.width.equalTo(@115.0f);
            make.height.equalTo(@57.0f);
        }];
        [self.showButton setBackgroundImage:[UIImage imageNamed:@"icon_message_other"] forState:UIControlStateNormal];
        //轉(zhuǎn)化率
        NSString * transRateStr = [[NSString stringWithFormat:@"%.2f",openCount/registerCount*100] stringByAppendingString:@"%"];
        [self.showButton setTitle:[NSString stringWithFormat:@"人數(shù): %.0f\n轉(zhuǎn)化率: %@",openCount,transRateStr] forState:UIControlStateNormal];
    }
    
    if (btn.tag == 5003) {
        [self.showButton mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(100 - thirdBtn.center.x);
            make.centerY.equalTo(thirdBtn);
            make.width.equalTo(@115.0f);
            make.height.equalTo(@57.0f);
        }];
        [self.showButton setBackgroundImage:[UIImage imageNamed:@"icon_message_other"] forState:UIControlStateNormal];
        //轉(zhuǎn)化率
        NSString * transRateStr = [[NSString stringWithFormat:@"%.2f",lendCount/openCount*100] stringByAppendingString:@"%"];
        [self.showButton setTitle:[NSString stringWithFormat:@"人數(shù): %.0f\n轉(zhuǎn)化率: %@",lendCount,transRateStr] forState:UIControlStateNormal];
    }
    if (btn.tag == 5004) {
        [self.showButton mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(100 - fourthBtn.center.x);
            make.centerY.equalTo(fourthBtn);
            make.width.equalTo(@115.0f);
            make.height.equalTo(@57.0f);
        }];
        [self.showButton setBackgroundImage:[UIImage imageNamed:@"icon_message_other"] forState:UIControlStateNormal];
        //轉(zhuǎn)化率
        NSString * transRateStr = [[NSString stringWithFormat:@"%.2f",repeatCount/lendCount*100] stringByAppendingString:@"%"];
        [self.showButton setTitle:[NSString stringWithFormat:@"人數(shù): %.0f\n轉(zhuǎn)化率: %@",repeatCount,transRateStr] forState:UIControlStateNormal];
    }
}
- (UIButton *)showButton{
    if (!_showButton) {
        _showButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _showButton.frame = CGRectMake(0, 0, 115, 57);
        [_showButton setTitleColor:[UIColor colorWithHex:666666] forState:UIControlStateNormal];
        _showButton.titleLabel.font = [UIFont systemFontOfSize:12];
        _showButton.titleEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0);
        _showButton.titleLabel.lineBreakMode = 0;
        [self addSubview:_showButton];   
    }
    return _showButton;
}

-(FHXChartNoDataView *)noDataView{
    if (!_noDataView) {
        _noDataView = [[NSBundle mainBundle]loadNibNamed:@"FHXChartNoDataView" owner:self options:nil][0];
        _noDataView.frame = self.bounds;
        [self addSubview:_noDataView];
        _noDataView.hidden = YES;
        [_noDataView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.equalTo(self);
            make.centerY.equalTo(self);
            make.width.equalTo(@128.0f);
            make.height.equalTo(@128.0f);
        }];   
    }
    return _noDataView;
}
@end

因?yàn)槭羌兇a創(chuàng)建的圖姐叁,所以借用了優(yōu)秀的Masonry庫來添加代碼約束瓦盛。因?yàn)檫@種圖在視覺上就是直觀的看一個(gè)數(shù)據(jù)轉(zhuǎn)化率,所以可以在計(jì)算每個(gè)點(diǎn)的位置的時(shí)候外潜,將數(shù)據(jù)整數(shù)化原环,使用整數(shù)來計(jì)算更方便,因?yàn)閷?shí)際數(shù)據(jù)是要通過點(diǎn)擊事件顯示出來的处窥,所以取整數(shù)計(jì)算點(diǎn)并繪圖嘱吗,不影響結(jié)果。

使用
1.創(chuàng)建funnlView(漏斗圖)

_funnelView = [[FHXFunnelView alloc]initWithFrame:CGRectMake(0, 64, SCREEN_WIDTH, 360)];
    [self.view addSubview:self.funnelView];
    [self initTestData];

2.添加數(shù)據(jù),使用隨機(jī)數(shù)模擬真實(shí)數(shù)據(jù)

//動(dòng)態(tài)添加數(shù)據(jù)
    FHXFunnelModel * funnelModel = [[FHXFunnelModel alloc]init];
    funnelModel.firstItemNum = [NSString stringWithFormat:@"%d",(arc4random() % 100) + 300];
    funnelModel.secondItemNum = [NSString stringWithFormat:@"%d",(arc4random() % 100) + 200];
    funnelModel.thirdItemNum = [NSString stringWithFormat:@"%d",(arc4random() % 100) + 100];
    funnelModel.fourthItemNum = [NSString stringWithFormat:@"%d",(arc4random() % 100) + 0];
    self.funnelView.funnelModel = funnelModel;
    //大標(biāo)題
    self.funnelView.title = @"用戶數(shù)據(jù)漏斗圖";
    //小標(biāo)題
    NSArray * array = @[@"注冊",@"開戶",@"綁卡",@"下單"];
    NSMutableArray * titleArray = [NSMutableArray arrayWithArray:array];
    self.funnelView.desArray = titleArray;

PS:實(shí)際應(yīng)用中谒麦,很多數(shù)據(jù)都是呈現(xiàn)漏斗圖的趨勢俄讹,類似“注冊用戶-->實(shí)名用戶-->下單用戶-->二次下單用戶”這種數(shù)據(jù),可根據(jù)實(shí)際需求绕德,定制各類數(shù)據(jù)漏斗圖患膛。下一步,將會(huì)對(duì)繪制動(dòng)畫做一下優(yōu)化耻蛇。

Demo鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末踪蹬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子臣咖,更是在濱河造成了極大的恐慌跃捣,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夺蛇,死亡現(xiàn)場離奇詭異枝缔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蚊惯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門愿卸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人截型,你說我怎么就攤上這事趴荸。” “怎么了宦焦?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵发钝,是天一觀的道長。 經(jīng)常有香客問我波闹,道長酝豪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任精堕,我火速辦了婚禮孵淘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘歹篓。我一直安慰自己瘫证,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布庄撮。 她就那樣靜靜地躺著背捌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪洞斯。 梳的紋絲不亂的頭發(fā)上毡庆,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼么抗。 笑死毅否,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的乖坠。 我是一名探鬼主播搀突,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼刀闷,長吁一口氣:“原來是場噩夢啊……” “哼熊泵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起甸昏,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤顽分,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后施蜜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卒蘸,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年翻默,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缸沃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡修械,死狀恐怖趾牧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肯污,我是刑警寧澤翘单,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蹦渣,受9級(jí)特大地震影響哄芜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柬唯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一认臊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锄奢,春花似錦美尸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至堪滨,卻和暖如春胯陋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工遏乔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留义矛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓盟萨,卻偏偏與公主長得像凉翻,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捻激,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容