直方圖主要用在數據圖表,作為對比數據,用柱體高度的高低,形象直觀地表達出來,往往與折線圖配合使用,而折線圖便于從眾多數據,在時間長度上看出,觀察對象發展的趨勢。下面直接上代碼,
1. 創建直方圖FangBarChart類。在FangBarChart.h中
#import "FangBarChart.h"
//#import "BGSDashLine.h"
#import "UILabel+verticalPlaceExtention.h"
#define HEXCOLOR(hexString) [UIColor colorWithRed:((float)((hexString & 0xFF0000) >> 16))/255.0 green:((float)((hexString & 0xFF00) >> 8))/255.0 blue:((float)(hexString & 0xFF))/255.0 alpha:1.0]
#define barWidth (BigBlank-xFirstSpace-xEndSpace)/(legendTextArray.count *2-1)
#define LeftSpaceY 40
#define BottomSpaceX 10
#define BigBlank (self.bounds.size.width-LeftSpaceY-BottomSpaceX)/roomNameArray.count
#define BigKeduHeight 5
#define bigBlankY (orginPoint.y-20)/(bxDataArrayY.count)//y軸每個大刻度實際值
#define LegendSpaceHorital 10
//#define legendLabelHeight 15
//#define YKedubxValue? maxYValue/(bxDataArrayY.count+1) //y軸每個大刻度表現值
@interface FangBarChart () {
NSMutableArray *bxDataArrayY;//客戶對該戶型房源關注度數據的顯示數據數組 y軸方向
NSMutableArray *rawDataArrayY;//客戶對該戶型房源關注度數據的繪畫數據數組? y軸方向
NSMutableArray *bxDataArrayX;//客戶對該戶型房源關注度數據的顯示數據數組? x軸方向
NSMutableArray *rawDataArrayX;//客戶對該戶型房源關注度數據的繪畫數據數組? x軸方向
NSMutableArray *fbBxDataArrayY;//經紀人對該戶型房源發布數據的顯示數據數組 y軸方向
NSMutableArray *myFbBXDatayArrayY;//您發布該戶型房源的情況
NSMutableArray *roomNameArray;//居室名字數組
BOOL showRectBoundary;//是否顯示當前視圖的矩形邊界
CGFloat YKedubxValue;//縱軸每個刻度值
CGPoint orginPoint;//原點
CGFloat xFirstSpace;//x軸上單個大刻度內的直方圖前面空余寬度
CGFloat xEndSpace;//x軸上單個大刻度內的直方圖最后面空余寬度
CGFloat legendVSpace; //圖例間的行間距
NSMutableArray *legendTextArray;//圖例提示文字數組
UIFont * xLabelFont;//橫軸直方圖label字體
UIColor *xLabelTextColor;//橫軸直方圖label字體顏色
UIFont *legendFont;//圖例文本字體
CGFloat legendLabelHeight;//圖例文本高度
LegendViewType legendPlaceType;//圖例放置方式
NSMutableArray *colorArray;//圖例和直方圖背景顏色數組,類型為uicolor
BOOL isShowYAsix; //
BOOL isShowXkedu;//是否顯示x軸刻度
BOOL isShowOrginXLabel;//是否顯示坐標原點x方向texLabel
CGFloat? maxYValue;//y軸 bar 數組展示數據最大值
CGFloat perPartbxValue;//y軸每個大刻度表現值
NSNumber *zhiDingMaxValue;//由接口指定的最大直方圖值 //y軸
XLabelPlaceType? xtextType;?
}
@property (nonatomic,strong)UIView *downLegendView;//圖例view
@property (nonatomic,strong)UIView *bgLineView;//barchart 背景橫線
property (nonatomic,strong)FangBarChartDataModel *dataModel;//設置直方圖相關自定義數據model
/**
直方圖利用數據model自定義方法
@param frame chartview 的frame
@param temModel 數據源model
@return 整個直方圖
*/
- (instancetype)initWithFrame:(CGRect)frame? withDataModel:(FangBarChartDataModel *)temModel;
/**
barchart 的刷新方法
@param nModel 提供新數據源的newmode
*/
- (void)refreshBarViewWithNewModel:(FangBarChartDataModel *)nModel;
@end
2.? 在FangBarChart.m中,主要 實現直方圖的初始化方法,以及刷新方法,初始化方法主要用于第一次初始設置一些數據,對直方圖,對每一組柱體 初始寬度設置。具體看代碼
@implementation FangBarChart
//先調用這個
- (instancetype)initWithFrame:(CGRect)frame? withDataModel:(FangBarChartDataModel *)temModel{
if (self=[super initWithFrame:frame]) {
//custom code here
//初始化客戶對該戶型房源關注度數據的顯示數據數組
//? ? ? ? [self numberToStringWithNumber:[NSNumber numberWithInt:1]];
self.dataModel=[[FangBarChartDataModel alloc]init];
if (temModel) {
self.dataModel=temModel;
}
self.dataModel.xtextType=XLabelPlaceTypeVertical;
[self getDataWithDataModel:self.dataModel];
if (legendTextArray>0) {
//創建圖例view
[self createLegendView];
}
}
return self;
}
(1)在這個方法中用到,數據源model,這個model 的屬性,作為自定義直方圖的各個參數。后面會講到這個FangBarChartDataModel。getDataWithDataModel:self.dataMode 中主要用self.dataModel 的屬性,初始化直方圖用到的各個數據。為了演示直方圖,我們使用了一些默認數據 。
- (void)getDataWithDataModel:(FangBarChartDataModel *)dataModel {
if (dataModel.xtextType==XLabelPlaceHorizital) {
xtextType=XLabelPlaceHorizital;
}else{
xtextType=XLabelPlaceTypeVertical;
}
CGFloat orginPointY=self.bounds.size.height-CGRectGetHeight(self.downLegendView.frame)-40;
orginPoint=CGPointMake(LeftSpaceY, orginPointY);
dataModel.xFirstSpace?xFirstSpace=dataModel.xFirstSpace:30;
dataModel.xEndSpace?xEndSpace=dataModel.xEndSpace:0;
NSLog(@"xfirst:%f,xend:%f",xFirstSpace,xEndSpace);
dataModel.legendVSpace?legendVSpace=dataModel.legendVSpace:7;
if (dataModel.fbBxDataArrayY) {
fbBxDataArrayY=dataModel.fbBxDataArrayY;
}else{
fbBxDataArrayY=[NSMutableArray arrayWithObjects:[NSNumber numberWithFloat:21.2],[NSNumber numberWithFloat:21.2],[NSNumber numberWithFloat:21.2],[NSNumber numberWithFloat:21.2],[NSNumber numberWithFloat:21.2],[NSNumber numberWithFloat:17], nil];
}
if (dataModel.myFbBXDatayArrayY) {
myFbBXDatayArrayY= dataModel.myFbBXDatayArrayY;
}else{
myFbBXDatayArrayY=[NSMutableArray arrayWithObjects:[NSNumber numberWithFloat:10],[NSNumber numberWithFloat:18],[NSNumber numberWithFloat:10],[NSNumber numberWithFloat:3],[NSNumber numberWithFloat:10],[NSNumber numberWithFloat:10] ,nil];//ceshi data
}
if (dataModel.roomNameArray) {
roomNameArray=dataModel.roomNameArray;
}else{
roomNameArray=[NSMutableArray arrayWithObjects:@"4:00",@"8:00",@"12:00",@"16:00",@"20:00",@"23:00", nil];
}
if (dataModel.bxDataArrayY) {
bxDataArrayY=dataModel.bxDataArrayY;
}else{
bxDataArrayY=[[NSMutableArray alloc]initWithObjects:[NSNumber numberWithFloat:13],[NSNumber numberWithFloat:12.9],[NSNumber numberWithFloat:23],[NSNumber numberWithFloat:19],[NSNumber numberWithFloat:18],[NSNumber numberWithFloat:5.5], nil];
}
rawDataArrayX=[[NSMutableArray alloc]initWithObjects:[NSNumber numberWithFloat:orginPoint.x+xFirstSpace+barWidth/2],[NSNumber numberWithFloat:orginPoint.x+BigBlank*1+xFirstSpace+barWidth/2],[NSNumber numberWithFloat:orginPoint.x+BigBlank*2+xFirstSpace+barWidth/2],[NSNumber numberWithFloat:orginPoint.x+BigBlank*3+xFirstSpace+barWidth/2],[NSNumber numberWithFloat:orginPoint.x+BigBlank*4+xFirstSpace+barWidth/2],[NSNumber numberWithFloat:orginPoint.x+BigBlank*5+xFirstSpace+barWidth/2], nil];
bxDataArrayX=[NSMutableArray arrayWithObjects:@"",@"",@"",@"",@"",@"", nil];
if (dataModel.legendTextArray) {
legendTextArray=dataModel.legendTextArray;
}else{
legendTextArray=[NSMutableArray arrayWithObjects:@"客戶關注",@"其他經紀人的發布",@"您的發布", nil];
}
if (dataModel.xLabelFont) {
xLabelFont=dataModel.xLabelFont;
}else{
xLabelFont=[UIFont systemFontOfSize:12];
}
if (dataModel.xLabelTextColor) {
xLabelTextColor=dataModel.xLabelTextColor;
}else{
xLabelTextColor=HEXCOLOR(0xbbbbbb);
}
if (dataModel.legendFont) {
legendFont=dataModel.legendFont;
}else{
legendFont=[UIFont systemFontOfSize:12];
}
if (dataModel.legendPlaceType) {
legendPlaceType=dataModel.legendPlaceType;
}else{
legendPlaceType=LegendViewTypeHorizital;
}
if (dataModel.colorArray) {
colorArray=dataModel.colorArray;
}else{
colorArray=[NSMutableArray arrayWithObjects:HEXCOLOR(0x7c8ec0),HEXCOLOR(0x78c5f1),HEXCOLOR(0xdbdbdb), nil];
}
//尋找數組最大值
if (dataModel.zhiDingMaxValue!=nil) {
maxYValue=[dataModel.zhiDingMaxValue floatValue];
}else{
CGFloat maxYValue0=[self lookforMaxValueWithArray:bxDataArrayY];
CGFloat maxYvalue1=[self lookforMaxValueWithArray:fbBxDataArrayY];
CGFloat maxYvalue2=[self lookforMaxValueWithArray:myFbBXDatayArrayY];
CGFloat tempMax=MAX(MAX(maxYValue0, maxYvalue1), maxYvalue2);
maxYValue=tempMax+0.5*(tempMax/bxDataArrayY.count);
NSLog(@"maxyvalue:%f",maxYValue);
}
perPartbxValue=maxYValue/(bxDataArrayY.count);
dataModel.showRectBoundary?showRectBoundary=dataModel.showRectBoundary:YES;
isShowYAsix=dataModel.isShowYAsix;
isShowXkedu=dataModel.isShowXkedu;
isShowOrginXLabel=YES;
}
在這個獲取初始化數據源的過程中,我們默認使用六組數據,也就是六組直方圖來初始化這個這個直方圖。我們默認是不顯示縱軸的,只顯示刻度label及其文本數據。請看圖
(2)在這個獲取數據源的數據中,看上圖,我們需要用到 定位 每個刻度 實際高度,
perPartbxValue=maxYValue/(bxDataArrayY.count);,其中maxvalue ,這些柱體y坐標代表數據的最大值轉化為實際繪圖高度的最大值,bxDataArrayY.coun,表示三個柱體為一組,這個直方圖共有多少組數。這個最大值如何尋找出來,我們封裝一個方法。
- (CGFloat)lookforMaxValueWithArray:(NSMutableArray *)marray { ??
?CGFloat? temMaxYValue=0;??
? if (marray.count>0) {? ??
? ? for (int k=0; ktvalue) ?(temMaxYValue=temMaxYValue) :(temMaxYValue=tvalue);
}
NSLog(@"temMaxYValue:%f",temMaxYValue);
}
return temMaxYValue;
}
這個方法便是從一個數組中尋找最大值。按上述方法從三組數組中尋求最大值,來作為直方圖上線。
(4)還有一個,如何把縱軸代表的值,轉化為實際繪圖的高度,我們也封裝了一個方法
- (CGFloat)rawYValue:(NSNumber *)yNum {
CGFloat yValue=(yNum.floatValue/perPartbxValue)*bigBlankY;
return yValue;
}
3.現在初始化數據準備的差不多,我們現在開始繪圖吧,為了每次在addsubuview 時候調用,我們把繪圖方法放在drawrect中,也便于更新數據再次調用。
//后addsubview 時候調用
- (void)drawRect:(CGRect)rect { ? ??
? ?if (legendTextArray>0) {??
? ? ? // Drawing code? ??
? ? //獲取當前環境? ??
? ? CGContextRef context=UIGraphicsGetCurrentContext();? ? ? ? //save context? ? ? ? CGContextSaveGState(context);? ??
? ? ? ? ? if (showRectBoundary) {? ? ?
?? ? ? //畫出矩形區域? ??
? ? ? ? CGRect rectAngle=rect;? ? ??
? ? ? //定義一個矩形路徑? ? ?
?? ? ? UIBezierPath * rectPath=[UIBezierPath bezierPathWithRect:rectAngle];?
?? ? ? ? ? //把矩形區域畫出來? ? ??
? ? ? ? ? ? ? ? ? [rectPath stroke];? ?
?? ? }? ? ? ?
?//開始畫x軸? ? ?
?? UIColor *strokeColor=HEXCOLOR(0xd4d4d5);? ?
?? ? [strokeColor set];??
? CGFloat orginPointY=self.bounds.size.height-CGRectGetHeight(self.downLegendView.frame)-40;? ? ? ? orginPoint=CGPointMake(LeftSpaceY, orginPointY);? ? ? ? //定義一個開始路徑? ? ? ? UIBezierPath *xStartPath=[UIBezierPath bezierPath];? ? ? ? [xStartPath setLineWidth:1.0];? ? ? ? [xStartPath moveToPoint:orginPoint];? ? ? ? [xStartPath addLineToPoint:CGPointMake(orginPoint.x, orginPoint.y+BigKeduHeight)];? ? ? ? //標注x軸原點label? ? ? ? if (isShowOrginXLabel) {? ? ? ? ? ? [self createOrginXLabel];? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? for (int i=0; i0) {
//
[self createBarWithIndex:p Color:colorArray[0] FromArray:bxDataArrayY orginx:xCenterValue-barWidth/2];
}
//畫其他經紀人對該戶型房源發布情況直方圖
NSString *agent=legendTextArray[1];
if (agent.length>0) {
[self createBarWithIndex:p Color:colorArray[1] FromArray:fbBxDataArrayY orginx:xCenterValue+barWidth*1.5];
}
//創建x軸線下居室提示label
[self createPromtLableWithOrginx:xCenterValue+(barWidth*2) index:p];
//畫您發布該戶型房源的情況直方圖
NSString *myFb=legendTextArray[2];
if (myFb.length>0) {
[self createBarWithIndex:p Color:colorArray[2] FromArray:myFbBXDatayArrayY orginx:xCenterValue+barWidth*3.5];
}
}
}
}
(1)在這個方法中首先用圖例文本數組legendTextArray,來定義是否會直方圖,legendTextArray 的count是否大于零,來定義是否繪圖,在圖例文本數組有數據的畫圖。而且count數目來代表,一組柱體到底畫幾組柱體。我們是根據UIgraphics 來獲取當前繪圖環境,并存儲,以供下次取用。并繪制一個矩形區域作為繪圖范圍,當然這個區域是我們繪圖方便需要,而不是項目需求,我們用showrect 這個Bool值來控制,yes 顯示這個區域,否則不顯示。請看代碼
//獲取當前環境
CGContextRef context=UIGraphicsGetCurrentContext();
//save context
CGContextSaveGState(context);
if (showRectBoundary) {
//畫出矩形區域
CGRect rectAngle=rect;
//定義一個矩形路徑
UIBezierPath * rectPath=[UIBezierPath bezierPathWithRect:rectAngle];
//把矩形區域畫出來
[rectPath stroke];
}
(2)下面是繪畫x軸線,并設置線條顏色,使用貝斯爾曲線作為繪制path
//開始畫x軸
UIColor *strokeColor=HEXCOLOR(0xd4d4d5);
[strokeColor set];
CGFloat orginPointY=self.bounds.size.height-CGRectGetHeight(self.downLegendView.frame)-40;
orginPoint=CGPointMake(LeftSpaceY, orginPointY);
//定義一個開始路徑
UIBezierPath *xStartPath=[UIBezierPath bezierPath];
[xStartPath setLineWidth:1.0];
[xStartPath moveToPoint:orginPoint];
[xStartPath addLineToPoint:CGPointMake(orginPoint.x, orginPoint.y+BigKeduHeight)];
//標注x軸原點label
if (isShowOrginXLabel) {
[self createOrginXLabel];
}
同樣的方法繪制y軸線 ,詳情請看drawret方法中的代碼。
(3)然后我們畫背景橫線,這里使用的實線的方法,也可以使用畫虛線的方法。
//畫背景橫線
for(int n=0; n<bxDataArrayY.count;n++ {
NSLog(@"n=%d",n);
UIView *lineView=[[UIView alloc]initWithFrame:CGRectMake(orginPoint.x, orginPoint.y-bigBlankY*(n+1)-0.5, rawDataArrayX.count *BigBlank, 1)];
lineView.backgroundColor=[UIColor lightGrayColor];
[self addSubview:lineView];
}
(4)畫6組直方圖,每一組直方圖中有三個柱體。
for (int p=0; p<rawDataArrayX.count;p++ {
//畫關注度直方圖
NSString *gz=legendTextArray[0];
NSNumber *xNum=rawDataArrayX[p];
CGFloat xCenterValue=xNum.floatValue;
if (gz.length>0) {
//
[self createBarWithIndex:p Color:colorArray[0] FromArray:bxDataArrayY orginx:xCenterValue-barWidth/2];
}
//畫其他經紀人對該戶型房源發布情況直方圖
NSString *agent=legendTextArray[1];
if (agent.length>0) {
[self createBarWithIndex:p Color:colorArray[1] FromArray:fbBxDataArrayY orginx:xCenterValue+barWidth*1.5];
}
//創建x軸線下居室提示label
[self createPromtLableWithOrginx:xCenterValue+(barWidth*2) index:p];
//畫您發布該戶型房源的情況直方圖
NSString *myFb=legendTextArray[2];
if (myFb.length>0) {
[self createBarWithIndex:p Color:colorArray[2] FromArray:myFbBXDatayArrayY orginx:xCenterValue+barWidth*3.5];
}
}
}
(5) 在drawrect中我們封裝創建原點xlabel,并封裝方法
- (void)createOrginXLabel{
NSString *text=@"0:00";
CGSize textSize;
if (text.length>0) {
textSize=[text sizeWithAttributes:@{NSFontAttributeName:xLabelFont}];
}
UILabel *xlabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, textSize.width,20)];
xlabel.center=CGPointMake(orginPoint.x, orginPoint.y+10);
xlabel.backgroundColor=[UIColor clearColor];
xlabel.font=xLabelFont;
[xlabel setTextColor:xLabelTextColor];
xlabel.text=text;
xlabel.textAlignment=NSTextAlignmentCenter;
xlabel.numberOfLines=0;
[xlabel setLineBreakMode:NSLineBreakByCharWrapping];
[self addSubview:xlabel];
}
其他非原點xlabel 我們也封裝了一個方法,并根據文字方向是橫向還是縱向,
- (void)createPromtLableWithOrginx:(CGFloat)orginx? index:(NSInteger)index{
NSString *text=roomNameArray[index];
CGSize textSize;
if (self.dataModel.xtextType==XLabelPlaceHorizital) {
//文字方向橫向排列
if (text.length>0) {
textSize=[text sizeWithAttributes:@{NSFontAttributeName:xLabelFont}];
}
UILabel *xlabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, textSize.width,20)];
xlabel.center=CGPointMake(orginx, orginPoint.y+10);
xlabel.backgroundColor=[UIColor clearColor];
xlabel.font=xLabelFont;
[xlabel setTextColor:xLabelTextColor];
xlabel.text=roomNameArray[index];
xlabel.textAlignment=NSTextAlignmentCenter;
xlabel.numberOfLines=0;
[xlabel setLineBreakMode:NSLineBreakByCharWrapping];
[self addSubview:xlabel];
}else{
if (text.length>0) {
if ([text containsString:@"-"])
{
NSArray *arr=[text componentsSeparatedByString:@"-"];
NSLog(@"array:%@",arr);
NSString *targetStr=@"";
if (arr.count==2)
{
targetStr=[targetStr stringByAppendingString:arr[0]];
targetStr=[targetStr stringByAppendingString:@"\n"];
targetStr=[targetStr stringByAppendingString:@"|"];
targetStr=[targetStr stringByAppendingString:@"\n"];
targetStr=[targetStr stringByAppendingString:arr[1]];
NSLog(@"targetstr:%@",targetStr);
//文字方向縱向排列
UILabel *xlabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, BigBlank,100)];
xlabel.center=CGPointMake(orginx, orginPoint.y+10+30);
xlabel.backgroundColor=[UIColor clearColor];
xlabel.font=xLabelFont;
[xlabel setTextColor:xLabelTextColor];
xlabel.text=targetStr;
xlabel.textAlignment=NSTextAlignmentCenter;
xlabel.numberOfLines=0;
[xlabel setLineBreakMode:NSLineBreakByCharWrapping];
[self addSubview:xlabel];
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc]initWithString:xlabel.text];
NSRange range = [xlabel.text rangeOfString:targetStr];? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //范圍
[attStr addAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor],
NSVerticalGlyphFormAttributeName:[NSNumber numberWithFloat:1]} range:range];//添加屬性
[xlabel setAttributedText:attStr];
CGSize targetSize=[text sizeWithAttributes:@{NSFontAttributeName:xLabelFont,NSVerticalGlyphFormAttributeName:[NSNumber numberWithFloat:1]}];
NSLog(@"textwidth:%f,textHeight:%f",targetSize.width,targetSize.height);
}
}
else{
//文字方向縱向排列
UILabel *xlabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, BigBlank,100)];
xlabel.center=CGPointMake(orginx, orginPoint.y+10+50);
xlabel.backgroundColor=[UIColor redColor];
xlabel.font=xLabelFont;
[xlabel setTextColor:xLabelTextColor];
xlabel.text=text;
xlabel.textAlignment=NSTextAlignmentCenter;
xlabel.numberOfLines=0;
[xlabel sizeToFit];
[xlabel setLineBreakMode:NSLineBreakByCharWrapping];
[self addSubview:xlabel];
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc]initWithString:xlabel.text];
NSRange range = [xlabel.text rangeOfString:text];? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //范圍
[attStr addAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor],
NSVerticalGlyphFormAttributeName:[NSNumber numberWithFloat:1]} range:range];//添加屬性
[xlabel setAttributedText:attStr];
}
}
if (text.length>0) {
textSize=[text sizeWithAttributes:@{NSFontAttributeName:xLabelFont}];
}
;
}
}
(6)同樣我們繪畫但個柱體,我們也封裝了方法,封裝這些方法,就是便于邏輯表達和方法調用,降低代碼耦合性。在繪畫柱體的過程中,我們同樣適用動畫,是柱體勻速增長
- ?(void)createBarWithIndex:(NSInteger)index Color:(UIColor *)bgColor FromArray:(NSMutableArray *)array orginx:(CGFloat)orginx ?{
NSNumber *yNum=array[index];
CGFloat yCenterValue=[self rawYValue:yNum];
CGRect barRect=CGRectMake(orginx,orginPoint.y-yCenterValue , barWidth, yCenterValue);
__block? float barH=0;
UIView *barView=[[UIView alloc]initWithFrame:CGRectMake(orginx,orginPoint.y-barH , barWidth, barH)];
barView.backgroundColor=bgColor;
[self addSubview:barView];
[UIView animateWithDuration:0.5 delay:0 options: UIViewAnimationOptionCurveEaseOut animations:^{
if (barH<=yCenterValue) {
barH+=5;
}
barView.frame=CGRectMake(orginx,orginPoint.y-barH , barWidth, barH);
} completion:^(BOOL finished){
barView.frame=barRect;
} ];
}
5.我們回到初始化方法,我們需要創建圖例view ,這個圖例,一般橫向圖例放置方式,當然也有縱向放置,我們默認使用橫向圖例。
- (void)createLegendView {
[self addSubview:self.downLegendView];
//客戶對該戶型房源的關注度 圖例
NSString*guzhu=legendTextArray[0];
UILabel *guzhuLabel;
if (guzhu.length>0) {
CGSize size=[guzhu sizeWithAttributes:@{NSFontAttributeName:legendFont}];
legendLabelHeight=size.height;
if (legendPlaceType==LegendViewTypeVertical) {
[self createLegendWithColor:colorArray[0] AndPromtLabelWithText:guzhu OnSuperView:self.downLegendView orginY:0];
}else{
guzhuLabel=[self createHoritalLegendWithColor:colorArray[0] AndPromtLabelWithText:guzhu OnSuperView:self.downLegendView orginX:(CGRectGetWidth(self.downLegendView.frame)-240)/2];
[self.downLegendView addSubview:guzhuLabel];
}
}
//其他經紀人對戶型房源的發布情況 圖例
NSString *qita=legendTextArray[1];
UILabel *agentLabel;
if (qita.length>0) {
if (legendPlaceType==LegendViewTypeVertical) {
[self createLegendWithColor:colorArray[1] AndPromtLabelWithText:qita OnSuperView:self.downLegendView orginY:legendLabelHeight+legendVSpace];
}else{
agentLabel=[self createHoritalLegendWithColor:colorArray[1] AndPromtLabelWithText:qita OnSuperView:self.downLegendView orginX:CGRectGetMaxX(guzhuLabel.frame)+LegendSpaceHorital];
[self.downLegendView addSubview:agentLabel];
}
}
//您發布該戶型房源的情況
NSString *fabu=legendTextArray[2];
UILabel *myFbLabel;
if (fabu.length>0) {
if (legendPlaceType==LegendViewTypeVertical) {
[self createLegendWithColor:colorArray[2] AndPromtLabelWithText:fabu OnSuperView:self.downLegendView orginY:(legendLabelHeight+legendVSpace)*2];
}else{
myFbLabel=[self createHoritalLegendWithColor:colorArray[2] AndPromtLabelWithText:fabu OnSuperView:self.downLegendView orginX:CGRectGetMaxX(agentLabel.frame)+LegendSpaceHorital];
[self.downLegendView addSubview:myFbLabel];
}
//? ? ? ? CGFloat legendVWidth=CGRectGetMaxX(myFbLabel.frame)-CGRectGetMinX(guzhuLabel.frame);
//? ? ? ? NSLog(@"legendvwidth:%f",legendVWidth);
}
}
(1)首先使用懶加載的方法創建總圖例view,看代碼
- (UIView *)downLegendView {
if (_downLegendView==nil) {
if (legendPlaceType==LegendViewTypeVertical) {
_downLegendView=[[UIView alloc]initWithFrame:CGRectMake(10, self.bounds.size.height-70, self.bounds.size.width-20, 60)];
}
else if (legendPlaceType==LegendViewTypeHorizital){
_downLegendView=[[UIView alloc]initWithFrame:CGRectMake(10, self.bounds.size.height-30, self.bounds.size.width-20, 20)];
}
//? ? ? ? _downLegendView.backgroundColor=[UIColor greenColor];
}
return _downLegendView;
}
(2)看圖,我們知道,每組圖例,有圖例和圖例文本組成。這樣我們封裝了一個方法
- (void)createLegendWithColor:(UIColor *)bgColor? AndPromtLabelWithText:(NSString *)text OnSuperView:(UIView *)spView? orginY:(CGFloat)y? {
//前面顏色圖標
CGSize size=[text sizeWithAttributes:@{NSFontAttributeName:legendFont}];
legendLabelHeight=size.height;
UIImageView *guzhuLegend=[[UIImageView? alloc]initWithFrame:CGRectMake(orginPoint.x, y, legendLabelHeight, legendLabelHeight)];
guzhuLegend.image=[self createLegendPointImageWithRadius:3 color:bgColor];
//? ? guzhuLegend.backgroundColor=bgColor;
[spView addSubview:guzhuLegend];
//后面解釋文字label
UILabel *promtLabel=[[UILabel alloc]initWithFrame:CGRectMake(CGRectGetMaxX(guzhuLegend.frame)+5, y,CGRectGetWidth(spView.frame)-CGRectGetMaxX(guzhuLegend.frame)-5, legendLabelHeight)];
promtLabel.text=text;
promtLabel.font=legendFont;
promtLabel.textAlignment=NSTextAlignmentLeft;
[spView addSubview:promtLabel];
}
其中,我們采用UIgraphics方法,自己繪制圖例,再生成圖片,而不是直接采用圖片的方式,見代碼如下
- (UIImage *)createLegendPointImageWithRadius:(CGFloat)radius color:(UIColor *)color {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(radius * 2,radius * 2), NO, 0);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, radius * 2, radius * 2) cornerRadius:radius];
[color setFill];
[path fill];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
上面是畫圖例豎直放置,當然也有水平放置圖例的,也封裝了一個 方法。
- (UILabel *)createHoritalLegendWithColor:(UIColor *)bgColor? AndPromtLabelWithText:(NSString *)text OnSuperView:(UIView *)spView? orginX:(CGFloat)x? {
//前面顏色圖標
CGSize size=[text sizeWithAttributes:@{NSFontAttributeName:legendFont}];
legendLabelHeight=size.height;
UIImageView *guzhuLegend=[[UIImageView? alloc]initWithFrame:CGRectMake(x, 0, 6, 6)];
guzhuLegend.center=CGPointMake(x+3, legendLabelHeight/2);
guzhuLegend.image=[self createLegendPointImageWithRadius:3 color:bgColor];
//? ? guzhuLegend.backgroundColor=bgColor;
[spView addSubview:guzhuLegend];
//后面解釋文字label
UILabel *promtLabel=[[UILabel alloc]initWithFrame:CGRectMake(CGRectGetMaxX(guzhuLegend.frame)+5, 0,size.width, legendLabelHeight)];
promtLabel.text=text;
promtLabel.font=legendFont;
promtLabel.textAlignment=NSTextAlignmentLeft;
//? ? [spView addSubview:promtLabel];
return promtLabel;
}
6. 最后我們看一下數據源model,在FangBarChartDataModel.h中
#import <Foundation/Foundation.h>
#import <UIkit/UIkit.h>
typedef enum {
LegendViewTypeHorizital=10,//圖例水平放置
LegendViewTypeVertical,//圖例豎直放置
} LegendViewType;
typedef enum {
XLabelPlaceHorizital=10,//x 軸下label文字水平放置
XLabelPlaceTypeVertical,//x 軸下label文字豎直放置
} XLabelPlaceType;
@interface FangBarChartDataModel : NSObject
@property (nonatomic)CGFloat xFirstSpace;//x軸大刻度內bar前空白距離
@property (nonatomic)CGFloat? xEndSpace;//x軸大刻度內bar前空白距離
@property (nonatomic)CGFloat legendVSpace;//bar 之間空白距離
@property (nonatomic,strong)NSMutableArray *fbBxDataArrayY;//經紀人對該戶型房源發布數據的顯示數據數組 y軸方向
@property (nonatomic,strong)NSMutableArray *myFbBXDatayArrayY;//您發布該戶型房源的情況
@property (nonatomic,strong)NSMutableArray *roomNameArray;//bar下標題數據源數組
@property (nonatomic,strong)NSMutableArray *bxDataArrayY;//客戶對該戶型房源關注度數據的顯示數據數組 y軸方向
@property (nonatomic)BOOL showRectBoundary;//是否顯示整個直方圖矩形邊緣
@property (nonatomic,strong)NSMutableArray *legendTextArray;//圖例提示文字數組
@property (nonatomic,strong)UIFont *xLabelFont;//bar下標題font
@property (nonatomic,strong)UIColor *xLabelTextColor;//bar下標題文本顏色
@property (nonatomic,strong)UIFont *legendFont;//圖例字體@property (nonatomic)LegendViewType legendPlaceType;//圖例放置方向,
@property (nonatomic,strong)NSMutableArray *colorArray;//圖例和直方圖bar填充yanse
@property (nonatomic)BOOL isShowYAsix;//是否顯示y軸
@property (nonatomic)BOOL isShowXkedu;//是否顯示x軸刻度
@property (nonatomic) BOOL isShowOrginXLabel;//是否顯示坐標原點x方向texLabel
@property (nonatomic,strong)? NSNumber *zhiDingMaxValue;//接口指定最大值;y軸
@property (nonatomic) LegendViewType legendPlaceType;
@property (nonatomic) XLabelPlaceType? xtextType;
@end
在import "FangBarChartDataModel.m"中
@implementation FangBarChartDataModel
@end
7.在代碼中使用自己封裝的 uilabel 文字,數字英文豎直排版的類別方法,在這個類別方法中采用在每個單詞間,單詞與數字或漢語間插入回車鍵,基本能達到數字排列文本的目的
先分享如下
@interface UILabel (verticalPlaceExtention)
@property (nonatomic) NSString *verticalText;
@end
#import "UILabel+verticalPlaceExtention.h"
#import "objc/Runtime.h"
@implementation UILabel (verticalPlaceExtention)
- (NSString *)verticalText{
// 利用runtime添加屬性
return objc_getAssociatedObject(self, @selector(verticalText));
}
- (void)setVerticalText:(NSString *)verticalText{
objc_setAssociatedObject(self, &verticalText, verticalText, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
NSMutableString *str = [[NSMutableString alloc] initWithString:verticalText];
NSInteger count = str.length;
for (int i = 1; i < count; i ++) {
[str insertString:@"\n" atIndex:i*2-1];
}
self.text = str;
self.numberOfLines = 0;
}
@end
本項目源碼地址:https://github.com/bianguangshengFang/FangBarScrollView.git