软件设计 2017-04-05
/** * 传入控件的内边距 创建整体控件 * * @param pieViewInset 饼图的内边距(相对于最近控件) * @param describeViewInset 描述控件的内边距(相对于最近控件) * * @return self 创建是不需要设置frame, 如设置 宽高传入(0, 0)即可 */ - (instancetype)bigViewWithPieViewEdgeInset:(UIEdgeInsets)pieViewInset DescribeViewEdgeInset:(UIEdgeInsets)describeViewInset;
PieView 和 DescribeView 的属性汇总 下面介绍这两个控件
/** 传入百分比数组 */ @property(nonatomic, strong) NSArray *scaleArr; /** 颜色数组 */ @property(nonatomic, strong) NSArray *colorArr; /** 线宽 默认 20 当线宽等于饼图半径时候 空心变成实心 */ @property(nonatomic, assign) CGFloat lineWidth; /** 饼图半径 默认35 当线宽等于饼图半径时候 空心变成实心 */ @property(nonatomic, assign) CGFloat pieViewRadius;
[blockquote]
属性 百分比数组 属性 颜色数组(可以多传颜色) 属性 线宽(饼图, 空心饼图) 属性 半径(和线宽配合使用)
[/blockquote]
/** * 一 传入的百分比数组, 返回转换为饼图使用的数组 * * @param scaleArr 百分比数组 * * @return pieView可用数组 */ - (NSArray *)changeScaleArrayToPieViewArray:(NSArray *)scaleArr;
/** * 二 创建饼图方法 * * @return self 不必设置frame */ - (instancetype)PieViewMaker;
typedef NS_ENUM(NSInteger, DesPositionType) {
kPositionTypeHorizontal = 0, //横向排列
kPositionTypeVertical //竖向排列
};
@interface DescribeView : UIView
/** 横竖向排列 默认竖向排列*/
@property(nonatomic, assign) DesPositionType positionStyle;
/** 按钮和label 字体大小 默认大小9 */
@property(nonatomic, assign) int labelFont ;
/** 控件内部按钮 和 label 空隙 默认5 */
@property(nonatomic, assign) CGFloat desButtonAndLabelMargin;
/** 控件之间的行高 默认5 */
@property(nonatomic, assign) CGFloat rowMargin;
/** 折行 默认3 */
@property(nonatomic, assign) int breakLineNumber;
/** label最大宽度 默认有多宽显示多宽*/
@property(nonatomic, assign) CGFloat maxLabelWidth;
/** view视图之间的间隔 默认5*/
@property(nonatomic, assign) CGFloat colMargin; [blockquote]
属性 横向排布, 还是竖向排布 属性 字体的大小 属性 左边方块和文字之间的空隙 属性 行间距 属性 到第几行折返到下一行(行, 列公用属性) 属性 文字最大显示多宽(默认有多宽显示多宽, 服务器应该计算好宽度) 属性 列间距
[/blockquote]
/** * 创建描述控件 * * @param describeArr 描述信息 * @param colorArr 颜色 * @param scaleArr 百分比 * * @return self 创建不必设置frame */ - (instancetype)describeInPieView:(NSArray *)describeArr withColorArr:(NSArray *)colorArr withScaleArr:(NSArray *)scaleArr;
应用drawRect:方法绘制
#pragma mark - 直接绘制 drawRect
- (void)drawRect:(CGRect)rect {
if (self.colorArr.count < self.scaleArr.count) {
return;
}
// 如果传入数组数量为零 则直接返回
if (self.scaleArr.count == 0) {
return;
} else {
UIBezierPath *path = [UIBezierPath bezierPath];
[path addArcWithCenter:self.center radius:_pieRadius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
[self adjust:path];
[path stroke];
}
} 百分比数组转换成饼图使用数组
#pragma mark - 将百分比穿换成pieView使用的百分比数组
- (NSArray *)changeScaleArrayToPieViewArray:(NSArray *)scaleArr
{
CGFloat total = 0.0f;
CGFloat start = 0.0f;
CGFloat end = 0.0f;
NSMutableArray *mScaleArr = [NSMutableArray array];
for (int i = 0; i < scaleArr.count; i ++) {
total += [scaleArr[i] floatValue];
end = M_PI * 2 * [scaleArr[i] floatValue] + start;
start = end;
[mScaleArr addObject:[NSNumber numberWithFloat:end]];
}
return [mScaleArr copy];
} 最后调用饼图制造者方法
#pragma mark - 饼图制造者
- (instancetype)PieViewMaker
{
if (self.colorArr.count < self.scaleArr.count) {
return nil;
}
//当线宽大于等于半径时候, 将为实心圆
if (self.lineWidth >= self.pieViewRadius) {
self.lineWidth = self.pieViewRadius;
}
CGRect pieViewFrame = self.frame;
pieViewFrame.size.width = self.pieViewRadius * 2;
pieViewFrame.size.height = self.pieViewRadius * 2;
self.frame = pieViewFrame;
//里面空心圆半径
_pieRadius = (self.frame.size.width - self.lineWidth) / 2;
// 如果传入数组数量为零 则直接返回
if (self.scaleArr.count == 0) {
return nil;
}
//如果传入数组数量为1, 则绘制整个圆
if (self.scaleArr.count == 1) {
return nil;
} else {
//否则正常绘制
for (int i = 0; i <= self.scaleArr.count - 2; i++) {
UIBezierPath *path = [UIBezierPath bezierPath];
[path addArcWithCenter:self.center radius:_pieRadius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
[self adjust:path];
[path stroke];
_bezierPath = [UIBezierPath bezierPath];
[_bezierPath addArcWithCenter:self.center radius:_pieRadius startAngle:[self.scaleArr[i] floatValue] endAngle:[self.scaleArr[i + 1] floatValue] clockwise:YES];
_shapeLayer = [CAShapeLayer layer];
_shapeLayer.frame = self.bounds;
_shapeLayer.path = _bezierPath.CGPath;
[self adjustPathAndShapeLayer:_bezierPath shapeLayer:_shapeLayer color:((UIColor *)self.colorArr[i + 1])];
[self.layer addSublayer:_shapeLayer];
}
}
return self;
} #pragma mark - 返回数组中最大值
- (float)returnMaxWidth:(NSArray *)numberArr
{
NSMutableArray *mTextArr = [NSMutableArray array];
for (int i = 0; i < numberArr.count; i++) {
CGRect frame = [numberArr[i] boundingRectWithSize:CGSizeMake(1000, 1000) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:_labelFont]} context:nil];
double width = frame.size.width;
[mTextArr addObject:[NSNumber numberWithFloat:width]];
}
return [[mTextArr valueForKeyPath:@"@max.intValue"] floatValue] + 1;
} #pragma mark - 创建描述控件
- (instancetype)describeInPieView:(NSArray<NSString *> *)describeArr withColorArr:(NSArray *)colorArr withScaleArr:(NSArray<NSNumber *> *)scaleArr
{
//容错: 数组元素显示不匹配将 直接return
if (colorArr.count < scaleArr.count || colorArr.count < describeArr.count || describeArr.count < scaleArr.count || scaleArr.count < describeArr.count) {
return nil;
}
//返回数组中最大字符串长度
CGFloat maxLabelWidth;
if (self.maxLabelWidth < 0.001) {
maxLabelWidth = [self returnMaxWidth:describeArr];
} else {
maxLabelWidth = self.maxLabelWidth;
}
for (int i = 0; i < describeArr.count; i++) {
[self setUpButtonWithDesArr:scaleArr colorArr:colorArr index:i];
}
if (describeArr.count == scaleArr.count) {
switch (self.positionStyle) {
case kPositionTypeVertical: // 竖向排列
{
for (int i = 0; i < describeArr.count; i++) {
//避免重赋值_viewHeight 和 _viewWidth
if (_viewHeight == 0.0) {
//显示View的高度
_viewHeight = _buttonHeight;
//显示View宽度
_viewWidth = _maxButtonWidth + maxLabelWidth + _desButtonAndLabelMargin;
//竖向排布frame计算
if (scaleArr.count <= _breakLineNumber) {
CGRect showViewWidth = self.frame;
showViewWidth.size.width = _viewWidth;
showViewWidth.size.height = (scaleArr.count - 1) * _rowMargin + scaleArr.count * _viewHeight;
self.frame = showViewWidth;
} else {
if (scaleArr.count % _breakLineNumber == 0) {
CGRect showViewWidth = self.frame;
showViewWidth.size.height = (scaleArr.count / _breakLineNumber) * _viewHeight + ((scaleArr.count / _breakLineNumber) - 1) * _rowMargin;
showViewWidth.size.width = (_colMargin * _breakLineNumber - 1) + _breakLineNumber * _viewWidth;
self.frame = showViewWidth;
} else {
CGRect showViewWidth = self.frame;
showViewWidth.size.width = ((scaleArr.count / _breakLineNumber) + 1) * _viewWidth + ((scaleArr.count / _breakLineNumber)) * _colMargin;
showViewWidth.size.height = (_colMargin * (_breakLineNumber - 1)) + _breakLineNumber * _viewHeight;
self.frame = showViewWidth;
}
}
}
//View 的x值
NSUInteger col = i / _breakLineNumber;
CGFloat viewX = col * (_viewWidth + _colMargin);
//View 的y值
NSUInteger row = i % _breakLineNumber;
CGFloat viewY = row * (_viewHeight + _rowMargin);
//创建按钮显示
UIButton * vScaleBtn = [self setUpButtonWithDesArr:scaleArr colorArr:colorArr index:i];
//创建文本详细显示
UILabel *vDesLabel = [self setUpLabelWithDescribeArr:describeArr index:i maxWidth:maxLabelWidth];
//创建底层View
UIView *showView = [[UIView alloc] initWithFrame:CGRectMake(viewX, viewY, _viewWidth, _viewHeight)];
// showView.backgroundColor = [UIColor redColor];
[showView addSubview:vDesLabel];
[showView addSubview:vScaleBtn];
[self addSubview:showView];
}
}
break;
//横向排布
case kPositionTypeHorizontal:
{
for (int i = 0; i < describeArr.count; i++) {
//避免重赋值_viewHeight
if (_viewHeight == 0.0) {
//显示View的高度
_viewHeight = _buttonHeight;
//显示View宽度
_viewWidth = _maxButtonWidth + maxLabelWidth + _desButtonAndLabelMargin;
//横向排布布局
if (scaleArr.count <= _breakLineNumber) {
CGRect showViewWidth = self.frame;
showViewWidth.size.width = _colMargin * (scaleArr.count - 1) + scaleArr.count * _viewWidth;
showViewWidth.size.height = _viewHeight;
self.frame = showViewWidth;
} else {
if (scaleArr.count % _breakLineNumber == 0) {
CGRect showViewWidth = self.frame;
showViewWidth.size.height = (scaleArr.count / _breakLineNumber) * _viewHeight + ((scaleArr.count / _breakLineNumber) - 1) * _rowMargin;
showViewWidth.size.width = (_colMargin * _breakLineNumber - 1) + _breakLineNumber * _viewWidth;
self.frame = showViewWidth;
} else {
CGRect showViewWidth = self.frame;
showViewWidth.size.height = ((scaleArr.count / _breakLineNumber) + 1) * _viewHeight + ((scaleArr.count / _breakLineNumber)) * _rowMargin;
showViewWidth.size.width = (_colMargin * (_breakLineNumber - 1)) + _breakLineNumber * _viewWidth;
self.frame = showViewWidth;
}
}
}
//View 的x值
NSUInteger col = i % _breakLineNumber;
CGFloat viewX = col * (_viewWidth + _colMargin);
//View 的y值
NSUInteger row = i / _breakLineNumber;
CGFloat viewY = row * (_viewHeight + _rowMargin);
//创建按钮显示
UIButton *hScaleBtn = [self setUpButtonWithDesArr:scaleArr colorArr:colorArr index:i];
//创建文本按钮
UILabel *hDesLabel = [self setUpLabelWithDescribeArr:describeArr index:i maxWidth:maxLabelWidth];
//创建底层View
UIView *showView = [[UIView alloc] initWithFrame:CGRectMake(viewX, viewY, _viewWidth, _viewHeight)];
[showView addSubview:hDesLabel];
[showView addSubview:hScaleBtn];
[self addSubview:showView];
}
}
break;
}
}
return self;
} #pragma mark - 创建控件
- (instancetype)bigViewWithPieViewEdgeInset:(UIEdgeInsets)pieViewInset DescribeViewEdgeInset:(UIEdgeInsets)describeViewInset
{
//容错: 数组元素显示不匹配将 直接return
if (self.colorArr.count < self.scaleArr.count || self.colorArr.count < self.describeArr.count || self.describeArr.count < self.scaleArr.count || self.scaleArr.count < self.describeArr.count) {
return nil;
}
// self.backgroundColor = [UIColor grayColor];
[self setUpPieViewAndDesView];
_pieViewInset = pieViewInset;
_desViewInset = describeViewInset;
//间隔距离
_pieViewAndDesViewMargin = fabs(_pieViewInset.right) ;
//设置desView在bigView中的位置
CGRect desViewFrame = _desView.frame;
desViewFrame.origin.x = fabs(_pieViewInset.left) + self.basePieView.frame.size.width + _pieViewAndDesViewMargin;
desViewFrame.origin.y = fabs(_desViewInset.top) ;
_desView.frame = desViewFrame;
//设置pieView在bigView中的位置
CGRect basePieViewFrame = self.basePieView.frame;
basePieViewFrame.origin.x = fabs(_pieViewInset.left) ;
basePieViewFrame.origin.y = fabs(_pieViewInset.top) ;
self.basePieView.frame = basePieViewFrame;
//根据pieView 和 desView 计算bigView的宽 和 高
CGRect bigViewFrame = self.frame;
if (self.basePieView.frame.size.height > self.desView.frame.size.height) {
bigViewFrame.size.height = fabs(_pieViewInset.top) + self.basePieView.frame.size.height + fabs(_pieViewInset.bottom);
bigViewFrame.size.width = fabs(_pieViewInset.left) + self.basePieView.frame.size.width + _pieViewAndDesViewMargin + _desView.frame.size.width + fabs(_desViewInset.right);
self.frame = bigViewFrame;
//当pieView的高度 大于 desView的高度 desView 居中与PieView
CGPoint desViewCenter = _desView.center;
desViewCenter.y = self.basePieView.center.y;
self.desView.center = desViewCenter;
} else {
bigViewFrame.size.height = fabs(_desViewInset.top) + _desView.frame.size.height + fabs(_desViewInset.bottom);
bigViewFrame.size.width = fabs(_pieViewInset.left) + self.basePieView.frame.size.width + _pieViewAndDesViewMargin + _desView.frame.size.width + fabs(_desViewInset.right);
self.frame = bigViewFrame;
//当pieView的高度 小于 desView的高度PieView 居中与 desView
CGPoint basePieViewCenter = self.basePieView.center;
basePieViewCenter.y = self.desView.center.y;
self.basePieView.center = basePieViewCenter;
}
return self;
} //模型
DescriptionModel *model = [DescriptionModel new];单独使用PieView
[blockquote]
警告⚠️: 1) 使用PieViews控件, 一定要在调用 "changeScaleArrayToPieViewArray:" 方法前设置属性. 2) 使用PieViews控件, 一定要先调用转换百分比方法 "changeScaleArrayToPieViewArray:" 再调用PieView制造者方法 "PieViewMaker" 3) 使用PieViews控件, 一定要在 "addSubView" 之前 调用 "changeScaleArrayToPieViewArray:" 方法 4) 单独使用PieViews控件,需要自己在PieViews控件外面包一层View,否则移动时会出现错乱. PieView使用顺序: 设置属性 > 调用"changeScaleArrayToPieViewArray:" > 调用"PieViewMaker" > 包一层View > addSubViw
[/blockquote]
/***********单独使用**************/
PieViews *pieView = [PieViews new];
pieView.lineWidth = 30;
pieView.pieViewRadius = 60;
pieView.colorArr = model.colorArr;
pieView.scaleArr = [pieView changeScaleArrayToPieViewArray:model.scaleArray];
[pieView PieViewMaker];
//包一层View
UIView *basePieView = [UIView new];
basePieView.frame = CGRectMake(20, 40, pieView.frame.size.width, pieView.frame.size.height);
[basePieView addSubview:pieView];
[self.view addSubview:basePieView];
/********************************/ 单独使用DescribeView
[blockquote]
无特殊警告⚠️
[/blockquote]
/***********单独使用**************/
DescribeView *desView = [DescribeView new];
desView.frame = CGRectMake(20, pieView.frame.size.height + 50, 0, 0);
desView.labelFont = 10;
desView.desButtonAndLabelMargin = 5;
desView.rowMargin = 5;
desView.colMargin = 5;
desView.breakLineNumber = 3;
desView.positionStyle = kPositionTypeVertical;
[desView describeInPieView:model.descriptionArray withColorArr:model.colorArr withScaleArr:model.scaleArray];
[self.view addSubview:desView];
/********************************/ 整体使用BigBackgroundView
[blockquote]
警告⚠️ 1) 使用BigBackGroundView控件时, 一定要在调用 "bigViewWithPieViewEdgeInset: DescribeViewEdgeInset:"方法前设置属性. 2) 设置center属性时, 要在 "bigViewWithPieViewEdgeInset: DescribeViewEdgeInset:"方法后设置. 直接设置frame无所谓.
BigBackgroundView使用顺序: 设置属性 > "bigViewWithPieViewEdgeInset: DescribeViewEdgeInset:" > 设置 center 属性(不了解为什么)
[/blockquote]
/***************整合*****************/
BigBackgroundView *showView = [BigBackgroundView new];
showView.pieViewRadius = 60;
showView.lineWidth = 30;
showView.positionStyle = kPositionTypeVertical;
showView.breakLineNumber = 5;
showView.colorArr = model.colorArr;
showView.scaleArr = model.scaleArray;
showView.describeArr = model.descriptionArray;
[self.view addSubview:showView];
[showView bigViewWithPieViewEdgeInset:UIEdgeInsetsMake(0, 0, 0, 10) DescribeViewEdgeInset:UIEdgeInsetsMake(0, 0, 0, 0)];
showView.center = self.view.center;
/********************************/ GitHub地址 安科开发地址 YGPieView地址