美文网首页
利用核心图形库创建自定义控件-动态血压图

利用核心图形库创建自定义控件-动态血压图

作者: 将军走路 | 来源:发表于2017-08-15 16:58 被阅读0次

这是我第一次在简书上写文章,主要是之前有点懒。最近经过某人的提醒,觉得是时候写点东西总结一下了。先写一下写博客的原因和动力。

  • 使自己理解的更加深刻;
  • 给自己立一些时间戳,可以看到时间的轨迹;
  • 给小伙伴们一些参考,看了很多大神的文章,使小弟进步不少;

先说自定义控件的原因:
UIKit并没有提供所有的控件样式,比如像一些柱状图、饼图、曲线图等。类似的应用例如股票类APP里会经常出现自定义的控件。

再说一下这次要做的样式:
用图表去显示一个人的血压情况,并且点击控件具体部分显示详情。
先上图

16CD126D-5F44-416E-9467-02116FFD0ABF.png
从图片可以看出控件细节还是很多的,所以需要分解一下,这样更加容易理解和实现。
所以步骤应该是:
  1. 画底部直线和中间虚线;
  2. 画圆圈的连接线;
  3. 画圆圈;
  4. 根据点击事件位置画详情消息界面;
  5. 根据逻辑在需要绘制的时候调用;
  6. 添加事件

下面是提供的画这些小图形的具体方法

1、画底部直线和中间虚线

/**
 画直线的方法

 @param startPoint 开始点
 @param endPoint 结束点
 */
- (void)drawVerticalLineAtstartPoint:(CGPoint)startPoint endPonit:(CGPoint)endPoint
{
    // 先获取当前画布(上下文)
    CGContextRef gc = UIGraphicsGetCurrentContext();
    // 创建一个路径
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, startPoint.x, startPoint.y);
    CGPathAddLineToPoint(path, NULL, endPoint.x, endPoint.y);
    // 将路径加到画布中去
    CGContextAddPath(gc, path);
    // 画布的参数设置
    CGContextSetStrokeColorWithColor(gc, self.lineBGColor.CGColor);
    CGContextSetLineWidth(gc, self.lineW);
    // 画布中画图
    CGContextDrawPath(gc, kCGPathFillStroke);
    // 最后不要忘了去释放路径
    CGPathRelease(path);
    
}
/**
 画虚线方法

 @param startPoint 起始点
 @param endPoint 结束点
 @param color 虚线的颜色
 */
- (void)drawDashVerticalLineAtstartPoint:(CGPoint)startPoint endPonit:(CGPoint)endPoint andColor:(UIColor *)color
{
    
    
    CGContextRef gc = UIGraphicsGetCurrentContext();
    
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, startPoint.x, startPoint.y);
    CGPathAddLineToPoint(path, NULL, endPoint.x, endPoint.y);
    
    CGContextAddPath(gc, path);
    // 虚线的间隔
    CGFloat lengths[] = {2,2};
    // 虚线的起始点
    CGContextSetLineDash(gc, 0, lengths,2);
    CGContextSetStrokeColorWithColor(gc, color.CGColor);
    CGContextSetLineWidth(gc, self.lineW);
    CGContextDrawPath(gc, kCGPathFillStroke);
    CGPathRelease(path);
    // 将画布环境设置为实线
    CGContextSetLineDash(gc, 0, NULL, 0);
    
}

2、圆点的画连接线

/**
 画连接线

 @param leftPoint 起始点
 @param rightPoint 结束点
 */
- (void)drawBezierLinkLineWithLeftPoint:(CGPoint)leftPoint rightPoint:(CGPoint)rightPoint
{
    // 此方法返回一个点,用来做控制点,
    CGPoint midPoint = midpoint(leftPoint, rightPoint);
    //用贝瑟尔曲线是为了微调连接线不至于僵硬
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:leftPoint];
    [path addQuadCurveToPoint:rightPoint controlPoint:midPoint];
    [path setLineWidth:self.linkLineW];
    CGContextRef gc = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(gc, self.linkLineColor.CGColor);
    [path stroke];
}

3、画圆圈

/**
 画圆圈

 @param color 颜色
 @param isFill 实心还是空心
 @param rect 画的位置
 */
- (void)drawCircleImageWithColor:(UIColor *)color isFill:(BOOL)isFill AtRect:(CGRect)rect
{
    CGContextRef gc = UIGraphicsGetCurrentContext();
    CGContextAddArc(gc, CGRectGetMidX(rect), CGRectGetMidY(rect), 5, 0, M_PI*2, 0);
    if (isFill) {
        CGContextSetFillColorWithColor(gc, color.CGColor);
    }
    else
    {
        CGContextSetFillColorWithColor(gc, [UIColor whiteColor].CGColor);
    }
    CGContextSetStrokeColorWithColor(gc, color.CGColor);
    
    CGContextDrawPath(gc, kCGPathFillStroke);
    
}

4、画消息框

/**
 画消息框

 @param point 消息框的尖尖指向的那个点
 @param color 消息框的背景颜色
 @param value 要显示的值
 */
- (void)drawTopMsgAtPoint:(CGPoint)point andColor:(UIColor *)color andValue:(CGFloat)value
{
    CGContextRef gc = UIGraphicsGetCurrentContext();
    
    
    
    CGMutablePathRef path = CGPathCreateMutable();
    
    
    CGFloat pointSpace = 6.0;
    CGFloat triangleH = 3.0;
    CGFloat rectWidth = 30.0;
    CGFloat rectHeight = 14.0;
    CGFloat triangleY = point.y-pointSpace;// 这里的点是三角形的尖尖
    CGFloat triangleX = point.x;
    CGFloat rato = 3.0;
    // 这里的点是三角形的尖尖
    CGPathMoveToPoint(path, NULL, triangleX, triangleY) ;
    // 画弧线
    CGPathAddArcToPoint(path, NULL, triangleX-triangleH, triangleY-triangleH, triangleX-rectWidth/2, triangleY-triangleH, rato);
    
    CGPathAddArcToPoint(path, NULL, triangleX-rectWidth/2, triangleY-triangleH, triangleX-rectWidth/2, triangleY-triangleH-rectHeight, rato);
    
    CGPathAddArcToPoint(path, NULL, triangleX-rectWidth/2, triangleY-triangleH-rectHeight, triangleX+rectWidth/2, triangleY-triangleH-rectHeight, rato);
    
    CGPathAddArcToPoint(path, NULL, triangleX+rectWidth/2, triangleY-triangleH-rectHeight, triangleX+rectWidth/2, triangleY-triangleH, rato);
    
    CGPathAddArcToPoint(path, NULL, triangleX+rectWidth/2, triangleY-triangleH, triangleX+triangleH, triangleY-triangleH, rato);
    
    CGPathAddArcToPoint(path, NULL, triangleX+triangleH, triangleY-triangleH, triangleX, triangleY, rato);
    
    CGContextAddPath(gc, path);
    
    CGContextSetFillColorWithColor(gc, color.CGColor);
    
    CGContextDrawPath(gc, kCGPathFillStroke);
    CGPathRelease(path);
    
    NSString * valueStr = [NSString stringWithFormat:@"%.0f",value];
    NSDictionary *valueAttributes = @{NSForegroundColorAttributeName:[UIColor whiteColor],NSFontAttributeName:[UIFont systemFontOfSize:12]};
    // 计算字符串的大小
    CGRect valueRect = [valueStr boundingRectWithSize:CGSizeMake(rectWidth, rectHeight) options:NSStringDrawingUsesLineFragmentOrigin attributes:valueAttributes context:nil];
    CGContextSaveGState(gc);
    // 画字符串
    [valueStr drawInRect:CGRectMake(triangleX-valueRect.size.width/2, triangleY-triangleH-rectHeight/2-valueRect.size.height/2, valueRect.size.width, valueRect.size.height) withAttributes:valueAttributes];
    CGContextRestoreGState(gc);
}

5、将这些方法在view绘制的时候通过一定的逻辑调用

这段代码内引用有其他逻辑,拷贝也不能运行,只是提供思路。

- (void)drawRect:(CGRect)rect {
    // Drawing code
    self.backgroundColor = [UIColor whiteColor];
    CGFloat lastStarY = 0;
    CGFloat lastEndY = 0;
    CGFloat lastX = 0;
    CGFloat maxSpaceValue = self.xueyaMaxandMinValue.topValue-self.xueyaMaxandMinValue.bottomValue;
    CGFloat maxSpacePt = self.topH-self.verticalSapce*2;
    // 这个比率是血压值和点的转换
    CGFloat rato = maxSpacePt/maxSpaceValue;
    // 根据数据去画界面
    for (int i = 0; i<self.xueYaValueArray.count; i++) {
        
        CGFloat x = self.spaceW+i*self.leftSpaceW;
        
        XueYaValue  *value = self.xueYaValueArray[i];
        
        CGFloat starY =  fabs(maxSpacePt - (value.topValue-self.xueyaMaxandMinValue.bottomValue)*rato)+self.verticalSapce;
        ;
        CGFloat endY = fabs(maxSpacePt - (value.bottomValue-self.xueyaMaxandMinValue.bottomValue)*rato)+self.verticalSapce;
        
        
        
        if (i<self.xueYaValueArray.count-1) {
            lastX = x+self.spaceW;
            XueYaValue  *lastValue = self.xueYaValueArray[i+1];
            lastStarY = fabs(maxSpacePt - (lastValue.topValue-self.xueyaMaxandMinValue.bottomValue)*rato)+self.verticalSapce;
            lastEndY = fabs(maxSpacePt - (lastValue.bottomValue-self.xueyaMaxandMinValue.bottomValue)*rato)+self.verticalSapce;
            
            
        }
        
        [self drawVerticalLineAtstartPoint:CGPointMake(x, 0) endPonit:CGPointMake(x, starY)];
        [self drawVerticalLineAtstartPoint:CGPointMake(x, endY) endPonit:CGPointMake(x, self.topH)];
        // 这里140,180,是临界点,用来区分颜色的
        if (value.topValue<140) {
            [self drawDashVerticalLineAtstartPoint:CGPointMake(x, starY) endPonit:CGPointMake(x, endY) andColor:[UIColor colorWithHexString:@"78B3F5"]];
        }
        else if(value.topValue<180)
        {
            [self drawDashVerticalLineAtstartPoint:CGPointMake(x, starY) endPonit:CGPointMake(x, endY) andColor:[UIColor colorWithHexString:@"D97F5C"]];
        }
        else
        {
            [self drawDashVerticalLineAtstartPoint:CGPointMake(x, starY) endPonit:CGPointMake(x, endY) andColor:[UIColor colorWithHexString:@"FF4B4B"]];
        }
        if (i<self.xueYaValueArray.count-1) {
            [self drawBezierLinkLineWithLeftPoint:CGPointMake(lastX, lastStarY) rightPoint:CGPointMake(x, starY)];
            [self drawBezierLinkLineWithLeftPoint:CGPointMake(lastX, lastEndY) rightPoint:CGPointMake(x, endY)];
        }
        
        if (value.topValue<140) {
            [self drawCircleImageWithColor:[UIColor colorWithHexString:@"78B3F5"] isFill:YES AtRect:CGRectMake(x-5, starY-5, 10, 10)];
            [self drawCircleImageWithColor:[UIColor colorWithHexString:@"78B3F5"] isFill:YES AtRect:CGRectMake(x-5, endY-5, 10, 10)];
        }
        else if (value.topValue<180)
        {
            [self drawCircleImageWithColor:[UIColor colorWithHexString:@"D97F5C"] isFill:YES AtRect:CGRectMake(x-5, starY-5, 10, 10)];
            [self drawCircleImageWithColor:[UIColor colorWithHexString:@"D97F5C"] isFill:YES AtRect:CGRectMake(x-5, endY-5, 10, 10)];
        }
        else
        {
            [self drawCircleImageWithColor:[UIColor colorWithHexString:@"FF4B4B"] isFill:YES AtRect:CGRectMake(x-5, starY-5, 10, 10)];
            [self drawCircleImageWithColor:[UIColor colorWithHexString:@"FF4B4B"] isFill:YES AtRect:CGRectMake(x-5, endY-5, 10, 10)];
        }
        
        [self drawTimeStrAtX:x andValue:value.timeStr];
        if (i>0) {
            XueYaValue *lastValue = self.xueYaValueArray[i-1];
            
            if(![value.dateStr isEqualToString:lastValue.dateStr])
            {
                [self drawDateStrAtX:x andValue:value.dateStr];
            }
        }
        else
        {
            [self drawDateStrAtX:x andValue:value.dateStr];
        }
        
        if ([self.currentValue isEqual:self.xueYaValueArray[i]]) {
            
            if (value.topValue<140) {
                [self drawBottomMsgAtPoint:CGPointMake(x, endY) andColor:[UIColor colorWithHexString:@"78B3F5"] andValue:self.currentValue.bottomValue];
                [self drawTopMsgAtPoint:CGPointMake(x, starY) andColor:[UIColor colorWithHexString:@"78B3F5"] andValue:self.currentValue.topValue];
            }
            else if (value.topValue<180)
            {
                [self drawBottomMsgAtPoint:CGPointMake(x, endY) andColor:[UIColor colorWithHexString:@"D97F5C"] andValue:self.currentValue.bottomValue];
                [self drawTopMsgAtPoint:CGPointMake(x, starY) andColor:[UIColor colorWithHexString:@"D97F5C"] andValue:self.currentValue.topValue];
            }
            else
            {
                [self drawBottomMsgAtPoint:CGPointMake(x, endY) andColor:[UIColor colorWithHexString:@"FF4B4B"] andValue:self.currentValue.bottomValue];
                [self drawTopMsgAtPoint:CGPointMake(x, starY) andColor:[UIColor colorWithHexString:@"FF4B4B"] andValue:self.currentValue.topValue];
            }  
        }
    }
}

6、最后添加事件

此处添加事件,画龙点睛。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = touches.anyObject;
    // 获取点击位置
    CGPoint point = [touch locationInView:self];
    // 计算需要交互的点
    NSInteger index = (point.x - self.leftSpaceW+self.spaceW/2)/self.spaceW;
    NSLog(@"点击位置为:%@",NSStringFromCGPoint(point));
    NSLog(@"点击index:%ld",index);
    
    if (self.xueYaValueArray.count>index) {
        // 此处存储需要绘制消息的内容
        self.currentValue = self.xueYaValueArray[index];
        // 刷新界面,重新绘制,
        [self setNeedsDisplay];
    }
}

总结

CoreGraphics 主要用于自定义控件,实线个性化需求。
关于CoreGraphics 官方这么说明

这是一个绘图专用的API族,它经常被称为QuartZ或QuartZ 2D。Core Graphics是iOS上所有绘图功能的基石,包括UIKit。

所以是一组很强大的API,需要我们后续学习。

相关文章

网友评论

      本文标题:利用核心图形库创建自定义控件-动态血压图

      本文链接:https://www.haomeiwen.com/subject/ajomrxtx.html