一、圓環(huán)型滑塊的設(shè)計
- 最近設(shè)計師設(shè)計了一個圓環(huán)型滑塊,其作用和UISlider差不多,用于拖動改變播放音頻的進度和指示音頻的播放進度。
-
大概的樣子如下圖:
圖一 設(shè)計圖 - 有如下的特點:
- 滑動的響應(yīng)區(qū)域為圓環(huán)上,并且靠近滑塊;
- 點擊滑塊時,滑塊有一個放大的動畫,手指離開屏幕時滑塊恢復(fù)原來大??;
- 當value=0%時,滑塊不可以再逆時針滑動,當value=100%時,滑塊不可以再順時針滑動。
- 最后我自己再加了一個設(shè)計,指示音頻loading的進度(這樣以來圓環(huán)就有了三層)。
二、成果展示Demo
Github 傳送門
- 重復(fù)滑動

圖二 重復(fù)滑動
- 限定360度和有l(wèi)oading的進度

圖三 限定360度
三、接入使用
1. 接入
直接將我的項目中ZCircleSlider文件夾中的ZCircleSlider.h 和 ZCircleSlider.m拖到項目中即可
2.使用
//ZCircleSlider的背景色是透明的,不會擋住下面View
- (ZCircleSlider *)circleSlider {
if (!_circleSlider) {
_circleSlider = [[ZCircleSlider alloc] initWithFrame:CGRectMake((kScreenWidth - 300) / 2.0, (kScreenHeight - 300) / 2.0, 300, 300)];
//走過的進度的顏色
_circleSlider.minimumTrackTintColor = kUIColorFromRGB(0x1482f0);
//loading進度的顏色。如果loading = 1,即loading完成,那么也是圓環(huán)的顏色,同于backgroundTintColor
_circleSlider.maximumTrackTintColor = kUIColorFromRGB(0xE62E2E);
//圓環(huán)的顏色
_circleSlider.backgroundTintColor = [UIColor colorWithWhite:0 alpha:0.2];
//圓環(huán)的寬
_circleSlider.circleBorderWidth = 5.0f;
//圓形滑塊的半徑
_circleSlider.thumbRadius = 8;
//圓形滑塊放大效果的半徑
_circleSlider.thumbExpandRadius = 12.5;
//圓形滑塊的顏色
_circleSlider.thumbTintColor = [UIColor redColor];
//圓環(huán)的半徑
_circleSlider.circleRadius = 260 / 2.0 + 2;
//設(shè)定初始值value = 0
_circleSlider.value = 0;
//設(shè)定loadingProgress的初始值 = 0
_circleSlider.loadProgress = 0;
//開始點擊,響應(yīng)事件
[_circleSlider addTarget:self
action:@selector(circleSliderTouchDown:)
forControlEvents:UIControlEventTouchDown];
//拖動過程中,響應(yīng)事件
[_circleSlider addTarget:self
action:@selector(circleSliderValueChanging:)
forControlEvents:UIControlEventValueChanged];
//拖動結(jié)束,響應(yīng)事件
[_circleSlider addTarget:self
action:@selector(circleSliderValueDidChanged:)
forControlEvents:UIControlEventTouchUpInside];
}
return _circleSlider;
}
#pragma mark - action
/*以下三個方法,都要添加對slider.interaction的判斷。
*因為雖然看起來是個圓環(huán),但是響應(yīng)手勢的區(qū)域確實整個矩形的View
*在內(nèi)部添加了interaction這個屬性用于限定響應(yīng)區(qū)域
*/
- (IBAction)circleSliderTouchDown:(ZCircleSlider *)slider {
if (!slider.interaction) {
return;
}
}
- (IBAction)circleSliderValueChanging:(ZCircleSlider *)slider {
if (!slider.interaction) {
return;
}
self.currentValueLabel.text = [NSString stringWithFormat:@"當前值:%.0f",slider.value * 100];
self.progressSlider.value = slider.value;
}
- (IBAction)circleSliderValueDidChanged:(ZCircleSlider *)slider {
if (!slider.interaction) {
return;
}
self.finalValueLabel.text = [NSString stringWithFormat:@"最終值:%.0f",slider.value * 100];
}
四、實現(xiàn)原理
簡單來說就是,整個控件繼承與UIControl,根據(jù)value,loadProgress的值改變重新繪制layer和改變thumb的位置;根據(jù)手勢所在的位置,重新繪制layer和改變thumb的位置,并改變value。
1. 根據(jù)所給value繪制圓弧
circleSlider.value和circleSlider.loadProgress,都是繪制圓弧。
1)在- (void)drawRect:(CGRect)rect;方法中繪制圓弧
在iOS中,圓的0弧度的位置是圓心(x,y)的正右側(cè)(x+r,y)
這里我選擇起始位置為-M_PI_2弧度,即圓心的正上方(x,y-r);
弧長對應(yīng)的變量就是運動的點相對于起點旋轉(zhuǎn)過的角度,而這個角度就等于value/1.0 * 360
下面給出了加載進度圓弧的繪制方法,value的圓弧繪制方法同理
- (void)drawRect:(CGRect)rect {
//加載的進度
UIBezierPath *loadPath = [UIBezierPath bezierPath];
CGFloat loadStart = -M_PI_2;
CGFloat loadCurre = loadStart + 2 * M_PI * self.loadProgress;
[loadPath addArcWithCenter:self.drawCenter
radius:self.radius
startAngle:loadStart
endAngle:loadCurre
clockwise:YES];
CGContextSaveGState(ctx);
CGContextSetShouldAntialias(ctx, YES);
CGContextSetLineWidth(ctx, self.circleBorderWidth);
CGContextSetStrokeColorWithColor(ctx, self.maximumTrackTintColor.CGColor);
CGContextAddPath(ctx, loadPath.CGPath);
CGContextDrawPath(ctx, kCGPathStroke);
CGContextRestoreGState(ctx);
}
2) 在值改變的時候重新繪制layer
在值改變的時候調(diào)用setNeedsDisplay方法重新繪制layer
- (void)setLoadProgress:(float)loadProgress {
_loadProgress = loadProgress;
[self setNeedsDisplay];
}
2.拖動控制,以及保證thumb(滑塊的那個圓點)在圓弧上運動
這里主要給出了解決的思路方法,具體的實現(xiàn)可到Github中查看
主要是在UIControl的以下三個方法上做文章:
//點擊開始
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
//拖動過程中
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
//拖動結(jié)束
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
1) 對于拖動控制,以及保證thumb在圓弧上運動可以通過以下這道數(shù)學(xué)題做抽象
1.設(shè)定平面直角坐標系原點為O(0,0),向右為x軸的正方向,向下為y軸的正方向;--------(iOS的屏幕坐標系)
2.在坐標系中有一個已知的圓C(a,b),半徑為r;--------(圓環(huán)型Slider)
3.平面內(nèi)任意一點S(m,n);--------(點擊的位置)
求:
1)點S到圓C的最短距離是否小于44;(限定點擊響應(yīng)的區(qū)域為圓弧內(nèi)外44個點的區(qū)域)
2)線段SC與圓的交點T(xT,yT);(thumb的位置,肯定在圓弧上)
3)線段ST的距離是否小于44;(限定點擊開始時的響應(yīng)區(qū)域為以thumb圓心,半徑為44的圓以內(nèi))
2) 對于當value=0%時,滑塊不可以再逆時針滑動,當value=100%時,滑塊不可以再順時針滑動。
1. 平面內(nèi)一個圓C半徑為r,其圓心位于坐標系原點,即C(0,0),圓弧上有一點T(x,y);
2. 坐標系可分為第一、二、三和四象限。
1)那么當點T相對于起始點(0,-r),順時針轉(zhuǎn)過的角度<60度時,禁止移動到第二,三,四象限;
2)當點T相對于起始點(0,-r),順時針轉(zhuǎn)過角度>300度時,禁止移動到第一,二,三象限;
