直方图主要用在数据图表,作为对比数据,用柱体高度的高低,形象直观地表达出来,往往与折线图配合使用,而折线图便于从众多数据,在时间长度上看出,观察对象发展的趋势。下面直接上代码,
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