
在開發(fā)過程中,有時(shí)候標(biāo)準(zhǔn)的 UIKit 控件并不能滿足我們的需求,這時(shí)候就需要我們自定義。
自定義控件可以參考系統(tǒng)中已有控件來(lái)實(shí)現(xiàn),比如 UIButton, ,UISegmentedControl, UISlider, UISwitch 等,它們都繼承自 UIControl。
先來(lái)看一張最終的效果:

該圓環(huán)控件可以做的事情:定制一個(gè)用戶界面,通過該界面用戶,可以在指定區(qū)域內(nèi)拖動(dòng)手柄,將當(dāng)前的角度轉(zhuǎn)化為需要顯示的數(shù)據(jù)。交互操作會(huì)被轉(zhuǎn)為控件的 Target 對(duì)應(yīng)的 Action。
完整的工程示例可以在這里下載:SFCircularSlider
繪制用戶界面
- 繪制底部圓環(huán)
CGContextSaveGState(context);
CGContextAddArc(context, kSelfWidth / 2, kSelfHeight / 2, _radius, -M_PI, M_PI * 2, 0);
[_circularColor setStroke];
CGContextSetLineWidth(context, _borderWidth);
CGContextSetLineCap(context, kCGLineCapButt);
CGContextDrawPath(context, kCGPathStroke);
CGContextRestoreGState(context);
這里繪制圓的方向,零度位于圓的最右側(cè),向上為負(fù)數(shù),向下是正數(shù)。
- 繪制填充區(qū)域
CGContextSaveGState(context);
CGContextAddArc(context, kSelfWidth / 2, kSelfHeight / 2, _radius,
DegreesToRadians(kCircleDegreeMin),
DegreesToRadians(kCircleDegree360 - _angle), 0);
[_minimumTrackTintColor setStroke];
CGContextSetLineWidth(context, _borderWidth);
CGContextSetLineCap(context, kCGLineCapRound); //設(shè)置線起點(diǎn)終點(diǎn)形狀
CGContextDrawPath(context, kCGPathStroke);
CGContextRestoreGState(context);
_angle 代表當(dāng)前角度,需要轉(zhuǎn)換到繪制角度上。繪制起點(diǎn)為最小值到當(dāng)前手勢(shì)所在位置。
- 繪制未填充區(qū)域圓弧
CGContextAddArc(context, kSelfWidth / 2, kSelfWidth / 2,
_radius, DegreesToRadians(kCircleDegree360 - _angle),
DegreesToRadians(kCircleDegreeMax), 0);
[_maximumTrackTintColor setStroke];
CGContextSetLineWidth(context, _borderWidth);
CGContextSetLineCap(context, kCGLineCapRound); //設(shè)置線起點(diǎn)終點(diǎn)形狀
CGContextDrawPath(context, kCGPathStroke);
未填充顏色區(qū)域原理相同,起點(diǎn)為手勢(shì)所在位置,終點(diǎn)為最大值處。
- 繪制手柄(thumb)
CGPoint handleCenter = [self pointFromAngle:_angle radius:_radius];
[_thumbTintColor set];
CGSize shadowOffset = CGSizeMake(0, 0);
CGFloat colorValues[] = {0, 0, 1/2, .6};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB ();
CGColorRef color = CGColorCreate (colorSpace, colorValues);
CGContextSetShadowWithColor(context, shadowOffset, 3, color);
CGContextFillEllipseInRect(context, CGRectMake(handleCenter.x - _thumbRadius,
handleCenter.y - _thumbRadius,
_thumbRadius * 2, _thumbRadius * 2));
CGContextSetLineCap(context, kCGLineCapButt);
CGContextDrawPath(context, kCGPathStroke);
CGColorRelease(color);
CGColorSpaceRelease(colorSpace);
手柄跟蹤當(dāng)前手勢(shì)所在的位置。為了增強(qiáng)立體感,添加投影的效果。CGContextSetShadowWithColor 中 offset 參數(shù)代表偏移的距離和方向,左負(fù)右正,上負(fù)下正,{0,0} 代表在一周上投影。
跟蹤用戶操作
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {}
通過重載 beginTracking 方法控制起始的觸發(fā)區(qū)域。
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event {}
重載 continueTracking 來(lái)連續(xù)跟蹤用戶的手勢(shì),并在超出響應(yīng)范圍之外返回 NO。
使用示例
SFCircularSlider *circularSlider = [[SFCircularSlider alloc] init];
circularSlider.value = 5;
circularSlider.minimumValue = 0;
circularSlider.maximumValue = 10;
circularSlider.minimumTrackTintColor = [UIColor colorWithRed:255/255.0 green:177/255.0 blue:0/255.0 alpha:1];
[circularSlider addTarget:self action:@selector(toucheUpInsideAction:) forControlEvents:UIControlEventTouchUpInside];
[circularSlider addTarget:self action:@selector(valueChangedAction:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:circularSlider];
支持設(shè)定最小/最大值,亦可接受 ValueChanged 和 TouchUpInside 的事件來(lái)響應(yīng)當(dāng)前拖動(dòng)的值和拖動(dòng)結(jié)束的值。