這是我第一次在簡(jiǎn)書(shū)上寫(xiě)文章,主要是之前有點(diǎn)懶铺韧。最近經(jīng)過(guò)某人的提醒多矮,覺(jué)得是時(shí)候?qū)扅c(diǎn)東西總結(jié)一下了。先寫(xiě)一下寫(xiě)博客的原因和動(dòng)力。
- 使自己理解的更加深刻塔逃;
- 給自己立一些時(shí)間戳讯壶,可以看到時(shí)間的軌跡;
- 給小伙伴們一些參考湾盗,看了很多大神的文章伏蚊,使小弟進(jìn)步不少;
先說(shuō)自定義控件的原因:
UIKit并沒(méi)有提供所有的控件樣式格粪,比如像一些柱狀圖躏吊、餅圖、曲線圖等帐萎。類(lèi)似的應(yīng)用例如股票類(lèi)APP里會(huì)經(jīng)常出現(xiàn)自定義的控件比伏。
再說(shuō)一下這次要做的樣式:
用圖表去顯示一個(gè)人的血壓情況,并且點(diǎn)擊控件具體部分顯示詳情疆导。
先上圖
從圖片可以看出控件細(xì)節(jié)還是很多的凳怨,所以需要分解一下,這樣更加容易理解和實(shí)現(xiàn)是鬼。
所以步驟應(yīng)該是:
- 畫(huà)底部直線和中間虛線肤舞;
- 畫(huà)圓圈的連接線;
- 畫(huà)圓圈均蜜;
- 根據(jù)點(diǎn)擊事件位置畫(huà)詳情消息界面李剖;
- 根據(jù)邏輯在需要繪制的時(shí)候調(diào)用;
- 添加事件
下面是提供的畫(huà)這些小圖形的具體方法
1囤耳、畫(huà)底部直線和中間虛線
/**
畫(huà)直線的方法
@param startPoint 開(kāi)始點(diǎn)
@param endPoint 結(jié)束點(diǎn)
*/
- (void)drawVerticalLineAtstartPoint:(CGPoint)startPoint endPonit:(CGPoint)endPoint
{
// 先獲取當(dāng)前畫(huà)布(上下文)
CGContextRef gc = UIGraphicsGetCurrentContext();
// 創(chuàng)建一個(gè)路徑
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, startPoint.x, startPoint.y);
CGPathAddLineToPoint(path, NULL, endPoint.x, endPoint.y);
// 將路徑加到畫(huà)布中去
CGContextAddPath(gc, path);
// 畫(huà)布的參數(shù)設(shè)置
CGContextSetStrokeColorWithColor(gc, self.lineBGColor.CGColor);
CGContextSetLineWidth(gc, self.lineW);
// 畫(huà)布中畫(huà)圖
CGContextDrawPath(gc, kCGPathFillStroke);
// 最后不要忘了去釋放路徑
CGPathRelease(path);
}
/**
畫(huà)虛線方法
@param startPoint 起始點(diǎn)
@param endPoint 結(jié)束點(diǎn)
@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};
// 虛線的起始點(diǎn)
CGContextSetLineDash(gc, 0, lengths,2);
CGContextSetStrokeColorWithColor(gc, color.CGColor);
CGContextSetLineWidth(gc, self.lineW);
CGContextDrawPath(gc, kCGPathFillStroke);
CGPathRelease(path);
// 將畫(huà)布環(huán)境設(shè)置為實(shí)線
CGContextSetLineDash(gc, 0, NULL, 0);
}
2篙顺、圓點(diǎn)的畫(huà)連接線
/**
畫(huà)連接線
@param leftPoint 起始點(diǎn)
@param rightPoint 結(jié)束點(diǎn)
*/
- (void)drawBezierLinkLineWithLeftPoint:(CGPoint)leftPoint rightPoint:(CGPoint)rightPoint
{
// 此方法返回一個(gè)點(diǎn),用來(lái)做控制點(diǎn)充择,
CGPoint midPoint = midpoint(leftPoint, rightPoint);
//用貝瑟爾曲線是為了微調(diào)連接線不至于僵硬
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德玫、畫(huà)圓圈
/**
畫(huà)圓圈
@param color 顏色
@param isFill 實(shí)心還是空心
@param rect 畫(huà)的位置
*/
- (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、畫(huà)消息框
/**
畫(huà)消息框
@param point 消息框的尖尖指向的那個(gè)點(diǎn)
@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;// 這里的點(diǎn)是三角形的尖尖
CGFloat triangleX = point.x;
CGFloat rato = 3.0;
// 這里的點(diǎn)是三角形的尖尖
CGPathMoveToPoint(path, NULL, triangleX, triangleY) ;
// 畫(huà)弧線
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]};
// 計(jì)算字符串的大小
CGRect valueRect = [valueStr boundingRectWithSize:CGSizeMake(rectWidth, rectHeight) options:NSStringDrawingUsesLineFragmentOrigin attributes:valueAttributes context:nil];
CGContextSaveGState(gc);
// 畫(huà)字符串
[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繪制的時(shí)候通過(guò)一定的邏輯調(diào)用
這段代碼內(nèi)引用有其他邏輯宰僧,拷貝也不能運(yùn)行,只是提供思路观挎。
- (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;
// 這個(gè)比率是血壓值和點(diǎn)的轉(zhuǎn)換
CGFloat rato = maxSpacePt/maxSpaceValue;
// 根據(jù)數(shù)據(jù)去畫(huà)界面
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,是臨界點(diǎn)嘁捷,用來(lái)區(qū)分顏色的
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造成、最后添加事件
此處添加事件,畫(huà)龍點(diǎn)睛雄嚣。
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
// 獲取點(diǎn)擊位置
CGPoint point = [touch locationInView:self];
// 計(jì)算需要交互的點(diǎn)
NSInteger index = (point.x - self.leftSpaceW+self.spaceW/2)/self.spaceW;
NSLog(@"點(diǎn)擊位置為:%@",NSStringFromCGPoint(point));
NSLog(@"點(diǎn)擊index:%ld",index);
if (self.xueYaValueArray.count>index) {
// 此處存儲(chǔ)需要繪制消息的內(nèi)容
self.currentValue = self.xueYaValueArray[index];
// 刷新界面晒屎,重新繪制,
[self setNeedsDisplay];
}
}
總結(jié)
CoreGraphics 主要用于自定義控件,實(shí)線個(gè)性化需求鼓鲁。
關(guān)于CoreGraphics 官方這么說(shuō)明
這是一個(gè)繪圖專(zhuān)用的API族履肃,它經(jīng)常被稱(chēng)為QuartZ或QuartZ 2D。Core Graphics是iOS上所有繪圖功能的基石坐桩,包括UIKit尺棋。
所以是一組很強(qiáng)大的API,需要我們后續(xù)學(xué)習(xí)绵跷。