使用UIBezierPath
畫圖步驟:
- 創建一個
UIBezierPath
對象 - 調用
-moveToPoint:
設置初始線段的起點 - 添加線或者曲線去定義一個或者多個子路徑
改變UIBezierPath
對象跟繪圖相關的屬性。如,我們可以設置畫筆的屬性、填充樣式等
UIBezierPath
創建方法介紹
我們先看看UIBezierPath
類提供了哪些創建方式,這些都是工廠方法,直接使用即可。
+ (instancetype)bezierPath; + (instancetype)bezierPathWithRect:(CGRect)rect; + (instancetype)bezierPathWithOvalInRect:(CGRect)rect; + (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; + (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii; + (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise; + (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;
本文主要是利用下面的方法繪制圓形,進而形成動態的速度表盤形式:
+ (instancetype)bezierPathWithArcCenter:(CGPoint)center
radius:(CGFloat)radius
startAngle:(CGFloat)startAngle
endAngle:(CGFloat)endAngle
clockwise:(BOOL)clockwise;
這個工廠方法用於畫弧,參數說明如下:
center
: 弧線中心點的坐標radius
: 弧線所在圓的半徑startAngle
: 弧線開始的角度值endAngle
: 弧線結束的角度值clockwise
: 是否順時針畫弧線
UIBezierPath* outArc=[UIBezierPath bezierPathWithArcCenter:LuCenter radius:self.arcRadius startAngle:startAngle endAngle:endAngle clockwise:YES]; CAShapeLayer* shapeLayer=[CAShapeLayer layer]; shapeLayer.lineWidth=lineWitdth; shapeLayer.fillColor=filleColor.CGColor; shapeLayer.strokeColor=strokeColor.CGColor; shapeLayer.path=outArc.CGPath; shapeLayer.lineCap=kCALineCapRound; [self.layer addSublayer:shapeLayer];
CAShapeLayer有着幾點很重要(使用CAShapeLayer與UIBezierPath可以實現不在view的drawRect方法中就畫出一些想要的圖形):
1. 它依附於一個給定的path,必須給與path,而且,即使path不完整也會自動首尾相接
2. strokeStart以及strokeEnd代表着在這個path中所占用的百分比
3. CAShapeLayer動畫僅僅限於沿着邊緣的動畫效果,它實現不了填充效果
下面介紹一下速度表盤的實現過程:
- 畫外圍弧度
/** * 畫弧度 * * @param startAngle 開始角度 * @param endAngle 結束角度 * @param lineWitdth 線寬 * @param filleColor 扇形填充顏色 * @param strokeColor 弧線顏色 */ -(void)drawArcWithStartAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle lineWidth:(CGFloat)lineWitdth fillColor:(UIColor*)filleColor strokeColor:(UIColor*)strokeColor{ //保存弧線寬度,開始角度,結束角度 self.lineWidth=lineWitdth; self.startAngle=startAngle; self.endAngle=endAngle; self.arcAngle=endAngle-startAngle; self.arcRadius=Calculate_radius; self.scaleRadius=self.arcRadius-self.lineWidth; self.scaleValueRadius=self.scaleRadius-self.lineWidth; self.speedLabel.text=@"0%"; UIBezierPath* outArc=[UIBezierPath bezierPathWithArcCenter:LuCenter radius:self.arcRadius startAngle:startAngle endAngle:endAngle clockwise:YES]; CAShapeLayer* shapeLayer=[CAShapeLayer layer]; shapeLayer.lineWidth=lineWitdth; shapeLayer.fillColor=filleColor.CGColor; shapeLayer.strokeColor=strokeColor.CGColor; shapeLayer.path=outArc.CGPath; shapeLayer.lineCap=kCALineCapRound; [self.layer addSublayer:shapeLayer]; }
- 繪制刻度,可以實現任意等分
/** * 畫刻度 * * @param divide 刻度幾等分 * @param remainder 刻度數 * @param strokeColor 輪廓填充顏色 * @param fillColor 刻度顏色 */ -(void)drawScaleWithDivide:(int)divide andRemainder:(NSInteger)remainder strokeColor:(UIColor*)strokeColor filleColor:(UIColor*)fillColor scaleLineNormalWidth:(CGFloat)scaleLineNormalWidth scaleLineBigWidth:(CGFloat)scaleLineBigWidth{ CGFloat perAngle=self.arcAngle/divide; //我們需要計算出每段弧線的起始角度和結束角度 //這里我們從- M_PI 開始,我們需要理解與明白的是我們畫的弧線與內側弧線是同一個圓心 for (NSInteger i = 0; i<= divide; i++) { CGFloat startAngel = (self.startAngle+ perAngle * i); CGFloat endAngel = startAngel + perAngle/5; UIBezierPath *tickPath = [UIBezierPath bezierPathWithArcCenter:LuCenter radius:self.scaleRadius startAngle:startAngel endAngle:endAngel clockwise:YES]; CAShapeLayer *perLayer = [CAShapeLayer layer]; if((remainder!=0)&&(i % remainder) == 0) { perLayer.strokeColor = strokeColor.CGColor; perLayer.lineWidth = scaleLineBigWidth; }else{ perLayer.strokeColor = strokeColor.CGColor;; perLayer.lineWidth = scaleLineNormalWidth; } perLayer.path = tickPath.CGPath; [self.layer addSublayer:perLayer]; } }
- 繪制刻度值,刻度值可以按照任意數值等分
/** * 畫刻度值,逆時針設定label的值,將整個儀表切分為N份,每次遞增儀表盤弧度的N分之1 * * @param divide 刻度值幾等分 */ -(void)DrawScaleValueWithDivide:(NSInteger)divide{ CGFloat textAngel =self.arcAngle/divide; if (divide==0) { return; } for (NSUInteger i = 0; i <= divide; i++) { CGPoint point = [self calculateTextPositonWithArcCenter:LuCenter Angle:-(self.endAngle-textAngel*i)]; NSString *tickText = [NSString stringWithFormat:@"%ld%%",(divide - i)*100/divide]; //默認label的大小23 * 14 UILabel *text = [[UILabel alloc] initWithFrame:CGRectMake(point.x - 8, point.y - 7, 30, 14)]; text.text = tickText; text.font = [UIFont systemFontOfSize:10.f]; text.textColor = [UIColor redColor]; text.textAlignment = NSTextAlignmentLeft; [self addSubview:text]; } } //默認計算半徑-10,計算label的坐標 - (CGPoint)calculateTextPositonWithArcCenter:(CGPoint)center Angle:(CGFloat)angel { CGFloat x = (self.scaleValueRadius+3*self.lineWidth)* cosf(angel); CGFloat y = (self.scaleValueRadius+3*self.lineWidth)* sinf(angel); return CGPointMake(center.x + x, center.y - y); }
- 進度條曲線
/** * 進度條曲線 * * @param fillColor 填充顏色 * @param strokeColor 輪廓顏色 */ - (void)drawProgressCicrleWithfillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor{ UIBezierPath *progressPath = [UIBezierPath bezierPathWithArcCenter:LuCenter radius:self.arcRadius startAngle:self.startAngle endAngle:self.endAngle clockwise:YES]; CAShapeLayer *progressLayer = [CAShapeLayer layer]; self.progressLayer = progressLayer; progressLayer.lineWidth = self.lineWidth+0.25f; progressLayer.fillColor = fillColor.CGColor; progressLayer.strokeColor = strokeColor.CGColor; progressLayer.path = progressPath.CGPath; progressLayer.strokeStart = 0; progressLayer.strokeEnd = 0.0; progressLayer.lineCap=kCALineCapRound; [self.layer addSublayer:progressLayer]; }
- 為進度條添加漸變圖層,圖層顏色是從左向右漸變
/** * 添加漸變圖層 * * @param colorGradArray 顏色數組,如果想達到紅-黃-紅效果,數組應該是紅,黃,紅 */ -(void)setColorGrad:(NSArray*)colorGradArray{ //漸變圖層 CALayer *gradientLayer = [CALayer layer]; CAGradientLayer *gradientLayer1 = [CAGradientLayer layer]; //增加漸變圖層,frame為當前layer的frame gradientLayer1.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); [gradientLayer1 setColors:colorGradArray]; [gradientLayer1 setStartPoint:CGPointMake(0, 1)]; [gradientLayer1 setEndPoint:CGPointMake(1, 1)]; [gradientLayer addSublayer:gradientLayer1]; [gradientLayer setMask:_progressLayer]; //用progressLayer來截取漸變層 [self.layer addSublayer:gradientLayer]; }
個人寫代碼喜歡添加注釋,可是在奈何文筆不行,表達不清,請移步到我的GitHub上下載Demo,如果有什么問題也可以給我發郵件,評論探討。