iOS-雷达数据图

这次简单的写一个关于雷达数据显示的案列,实现简单,主要用UIBezierPath以及CAShapeLayer,如下图:
iOS-雷达数据图_第1张图片
具体实现:

思路:如何绘制上图中的六边形?我们只需要确定最外层六边形的边长(确定大小)和六边形的中心点的坐标(确定位置)。绘制几层六边形可以随意控制(把边平分几段)。然后添加每个顶点旁边的文本。最后根据相应的数据值绘制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];

Demo下载地址:https://github.com/MichaelSSY/HexagonBerizeView

你可能感兴趣的:(iOS开发笔记)