這次簡單的寫一個關於雷達數據顯示的案列,實現簡單,主要用UIBezierPath
以及CAShapeLayer
,如下圖:
具體實現:
思路:如何繪製上圖中的六邊形?我們只需要確定最外層六邊形的邊長(確定大小)和六邊形的中心點的座標(確定位置)。繪製幾層六邊形可以隨意控制(把邊平分幾段)。然後添加每個頂點旁邊的文本。最後根據相應的數據值繪製layer
(顏色層)。
實現代碼:
1、初始化默認數據:
- (void)configureDefaultData
{
_lineWidth = 0.5;
_valueWidth = 0.8;
_maxValue = 100.0;///<最大值,默認100(對應產品需求數據裏面的最大值)
_perAngle = 2 * M_PI / SideCount;
//默認六邊形在view的中間位置(任意調整)
_centerPoint = CGPointMake(self.yy_width * 0.5, self.yy_height * 0.5);
//根據中間點和邊長就可以確定六邊形最外層六個點座標;如果知道層數那麼就可以確定每一層六邊形的每個點的座標
_sideLength = 100.0;//默認六邊形邊長爲 100
_layerCount = 5;//默認層數爲 5 層
_layerStrokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.2];
_layerFillColor = [UIColor clearColor];
}
2、繪製六邊形:
//分割 num 後每格長度
CGFloat dLength = _sideLength / _layerCount;
// CGFloat sinV = sin(Degrees_To_Radians(30));//sin30度值
// CGFloat cosV = cos(Degrees_To_Radians(30));//cos30度值
// 繪製 num 個六邊形
for (NSInteger i = 0; i < _layerCount; i ++) {
//每一層邊長
CGFloat perSideLength = _sideLength - (dLength * i);
//每一層貝塞爾曲線
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
//確定六個頂點座標
for (NSInteger j = 0; j < SideCount; j++) {
CGPoint tempPoint = CGPointMake(_centerPoint.x - perSideLength * cos(_perAngle * (j+1)) ,_centerPoint.y - perSideLength * sin(_perAngle * (j+1)));
if (j == 0) {
[bezierPath moveToPoint:tempPoint];
} else {
[bezierPath addLineToPoint:tempPoint];
}
//保存最外層六邊形的六個頂點座標
if (i == 0) {
[self.outerLayerPoints addObject:[NSValue valueWithCGPoint:tempPoint]];
}
}
[bezierPath closePath];
CAShapeLayer *aLayer = [CAShapeLayer layer];
aLayer.lineWidth = _lineWidth;
aLayer.fillColor = _layerFillColor.CGColor;
aLayer.strokeColor = _layerStrokeColor.CGColor;
aLayer.lineCap = kCALineCapSquare;
aLayer.path = bezierPath.CGPath;
[self.layer addSublayer:aLayer];
}
//各個定點向中心點連線
for (NSInteger i = 0; i < self.outerLayerPoints.count; i++) {
CGPoint point = [self.outerLayerPoints[i] CGPointValue];
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:point];
[bezierPath addLineToPoint:_centerPoint];
CAShapeLayer *aLayer = [CAShapeLayer layer];
aLayer.lineWidth = _lineWidth;
aLayer.fillColor = _layerFillColor.CGColor;
aLayer.strokeColor = _layerStrokeColor.CGColor;
aLayer.lineCap = kCALineCapSquare;
aLayer.path = bezierPath.CGPath;
[self.layer addSublayer:aLayer];
}
3、繪製數據值層:
- (void)initValuePoint
{
//移除之前的值layer
for (CAShapeLayer *layer in self.layerArray) {
[layer removeFromSuperlayer];
}
[self.layerArray removeAllObjects];
for (NSInteger i = 0; i < _values.count; i ++) {
NSArray *templeValues = _values[i];
//繪製
UIBezierPath *path = [UIBezierPath bezierPath];
for (NSInteger j = 0; j < templeValues.count; j++) {
CGFloat value = [[templeValues objectAtIndex:j] floatValue];
//注意:這裏最大值以及邊長默認設置都是100
//value = value > _sideLength ? _sideLength : value;
//換算
value = (value / _maxValue) * _sideLength > _sideLength ? _sideLength : (value / _maxValue) * _sideLength;
CGPoint tempPoint = CGPointMake(_centerPoint.x - value * cos(_perAngle * (j+1)) ,_centerPoint.y - value * sin(_perAngle * (j+1)));
if (j == 0) {
[path moveToPoint:tempPoint];
} else {
[path addLineToPoint:tempPoint];
}
}
[path closePath];
CGFloat red = arc4random() % 256;
CGFloat green = arc4random() % 256;
CGFloat blue = arc4random() % 256;
CAShapeLayer *shaper = [CAShapeLayer layer];
shaper.path = path.CGPath;
shaper.lineWidth = _valueWidth;
//如果有顏色就採用用戶賦值的顏色;如果沒有顏色就隨機顏色
if (self.valueFillColors.count == self.values.count) {
shaper.fillColor = self.valueFillColors[i].CGColor;
} else {
shaper.fillColor = [UIColor colorWithRed:red/256.0 green:green/256.0 blue:blue/256.0 alpha:0.4].CGColor;
}
if (self.valueStrokeColors.count == self.values.count) {
shaper.strokeColor = self.valueStrokeColors[i].CGColor;
} else {
shaper.strokeColor = [UIColor colorWithRed:red/256.0 green:green/256.0 blue:blue/256.0 alpha:0.7].CGColor;
}
[self.layer addSublayer:shaper];
[self.layerArray addObject:shaper];
}
}
4、添加頂點處文案:
- (void)initLabel
{
//移除之前的label
for (UILabel *label in self.labelArray) {
[label removeFromSuperview];
}
[self.labelArray removeAllObjects];
//label的高度這裏寫死,可以根據需求設置寬度
CGFloat labelH = 20.0;
CGFloat fontSize = 15.0;
CGFloat space = 5.0;
for (NSInteger i = 0; i < _textArray.count; i++) {
CGPoint point = [self.outerLayerPoints[i] CGPointValue];
CGFloat width = [self sizeOfStringWithMaxSize:CGSizeMake(MAXFLOAT, labelH) textFont:fontSize aimString:_textArray[i]].width;
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, width, labelH)];
titleLabel.font = [UIFont systemFontOfSize:fontSize];
titleLabel.textColor = [[UIColor grayColor] colorWithAlphaComponent:0.6];
titleLabel.text = _textArray[i];
[self addSubview:titleLabel];
switch (i) {
case 0:
titleLabel.center = CGPointMake(point.x, point.y - labelH / 2 - space);
break;
case 1:
titleLabel.center = CGPointMake(point.x, point.y - labelH / 2 - space);
break;
case 2:
titleLabel.center = CGPointMake(point.x + width / 2 + space, point.y);
break;
case 3:
titleLabel.center = CGPointMake(point.x, point.y + labelH / 2 + space);
break;
case 4:
titleLabel.center = CGPointMake(point.x, point.y + labelH / 2 + space);
break;
case 5:
titleLabel.center = CGPointMake(point.x - width / 2 -space, point.y);
break;
default:
break;
}
[self.labelArray addObject:titleLabel];
}
}
5、外部調用方式:
- (HexagonBerizeView *)hexagonView
{
if (_hexagonView == nil) {
_hexagonView = [[HexagonBerizeView alloc] initWithFrame:CGRectMake(0, 64, ScreenWidth, 300)];
_hexagonView.textArray = @[@"客戶關係",@"產品",@"價格",@"品牌",@"服務",@"其他"];;
_hexagonView.valueFillColors = @[[UIColor colorWithRed:7/ 256.0 green:71/256.0 blue:151 / 256.0 alpha:0.4],[UIColor colorWithRed:255/ 256.0 green:0/256.0 blue:0 / 256.0 alpha:0.4]];
_hexagonView.valueStrokeColors = @[[UIColor colorWithRed:7/ 256.0 green:71/256.0 blue:151 / 256.0 alpha:0.7],[UIColor colorWithRed:255/ 256.0 green:0/256.0 blue:0 / 256.0 alpha:0.7]];
//這裏最大值取100 (根據需求而定)
_hexagonView.values = @[@[@(arc4random() % 100),@(arc4random() % 100),@(arc4random() % 100),@(arc4random() % 100),@(arc4random() % 100),@(arc4random() % 100)],
@[@(arc4random() % 100),@(arc4random() % 100),@(arc4random() % 100),@(arc4random() % 100),@(arc4random() % 100),@(arc4random() % 100)]];
}
return _hexagonView;
}
[self.view addSubview:self.hexagonView];