一勺择、圓環(huán)型滑塊的設(shè)計(jì)
- 最近設(shè)計(jì)師設(shè)計(jì)了一個(gè)圓環(huán)型滑塊,其作用和UISlider差不多床佳,用于拖動(dòng)改變播放音頻的進(jìn)度和指示音頻的播放進(jìn)度导俘。
-
大概的樣子如下圖:
圖一 設(shè)計(jì)圖 - 有如下的特點(diǎn):
- 滑動(dòng)的響應(yīng)區(qū)域?yàn)閳A環(huán)上,并且靠近滑塊驳概;
- 點(diǎn)擊滑塊時(shí)赤嚼,滑塊有一個(gè)放大的動(dòng)畫,手指離開屏幕時(shí)滑塊恢復(fù)原來大兴秤帧更卒;
- 當(dāng)value=0%時(shí),滑塊不可以再逆時(shí)針滑動(dòng)稚照,當(dāng)value=100%時(shí)蹂空,滑塊不可以再順時(shí)針滑動(dòng)。
- 最后我自己再加了一個(gè)設(shè)計(jì)锐锣,指示音頻loading的進(jìn)度(這樣以來圓環(huán)就有了三層)腌闯。
二、成果展示Demo
Github 傳送門
- 重復(fù)滑動(dòng)
圖二 重復(fù)滑動(dòng)
- 限定360度和有l(wèi)oading的進(jìn)度
圖三 限定360度
三雕憔、接入使用
1. 接入
直接將我的項(xiàng)目中ZCircleSlider文件夾中的ZCircleSlider.h 和 ZCircleSlider.m
拖到項(xiàng)目中即可
2.使用
//ZCircleSlider的背景色是透明的,不會(huì)擋住下面View
- (ZCircleSlider *)circleSlider {
if (!_circleSlider) {
_circleSlider = [[ZCircleSlider alloc] initWithFrame:CGRectMake((kScreenWidth - 300) / 2.0, (kScreenHeight - 300) / 2.0, 300, 300)];
//走過的進(jìn)度的顏色
_circleSlider.minimumTrackTintColor = kUIColorFromRGB(0x1482f0);
//loading進(jìn)度的顏色糖声。如果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;
//開始點(diǎn)擊琉苇,響應(yīng)事件
[_circleSlider addTarget:self
action:@selector(circleSliderTouchDown:)
forControlEvents:UIControlEventTouchDown];
//拖動(dòng)過程中嘲玫,響應(yīng)事件
[_circleSlider addTarget:self
action:@selector(circleSliderValueChanging:)
forControlEvents:UIControlEventValueChanged];
//拖動(dòng)結(jié)束,響應(yīng)事件
[_circleSlider addTarget:self
action:@selector(circleSliderValueDidChanged:)
forControlEvents:UIControlEventTouchUpInside];
}
return _circleSlider;
}
#pragma mark - action
/*以下三個(gè)方法并扇,都要添加對(duì)slider.interaction的判斷去团。
*因?yàn)殡m然看起來是個(gè)圓環(huán),但是響應(yīng)手勢(shì)的區(qū)域確實(shí)整個(gè)矩形的View
*在內(nèi)部添加了interaction這個(gè)屬性用于限定響應(yīng)區(qū)域
*/
- (IBAction)circleSliderTouchDown:(ZCircleSlider *)slider {
if (!slider.interaction) {
return;
}
}
- (IBAction)circleSliderValueChanging:(ZCircleSlider *)slider {
if (!slider.interaction) {
return;
}
self.currentValueLabel.text = [NSString stringWithFormat:@"當(dāng)前值:%.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];
}
四穷蛹、實(shí)現(xiàn)原理
簡(jiǎn)單來說就是土陪,整個(gè)控件繼承與UIControl,根據(jù)value肴熏,loadProgress的值改變重新繪制layer和改變thumb的位置鬼雀;根據(jù)手勢(shì)所在的位置,重新繪制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);
弧長(zhǎng)對(duì)應(yīng)的變量就是運(yùn)動(dòng)的點(diǎn)相對(duì)于起點(diǎn)旋轉(zhuǎn)過的角度泼诱,而這個(gè)角度就等于value/1.0 * 360
下面給出了加載進(jìn)度圓弧的繪制方法坛掠,value的圓弧繪制方法同理
- (void)drawRect:(CGRect)rect {
//加載的進(jìn)度
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) 在值改變的時(shí)候重新繪制layer
在值改變的時(shí)候調(diào)用setNeedsDisplay
方法重新繪制layer
- (void)setLoadProgress:(float)loadProgress {
_loadProgress = loadProgress;
[self setNeedsDisplay];
}
2.拖動(dòng)控制,以及保證thumb(滑塊的那個(gè)圓點(diǎn))在圓弧上運(yùn)動(dòng)
這里主要給出了解決的思路方法坷檩,具體的實(shí)現(xiàn)可到Github中查看
主要是在UIControl的以下三個(gè)方法上做文章:
//點(diǎn)擊開始
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
//拖動(dòng)過程中
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
//拖動(dòng)結(jié)束
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
1) 對(duì)于拖動(dòng)控制却音,以及保證thumb在圓弧上運(yùn)動(dòng)可以通過以下這道數(shù)學(xué)題做抽象
1.設(shè)定平面直角坐標(biāo)系原點(diǎn)為O(0,0),向右為x軸的正方向矢炼,向下為y軸的正方向系瓢;--------(iOS的屏幕坐標(biāo)系)
2.在坐標(biāo)系中有一個(gè)已知的圓C(a,b),半徑為r句灌;--------(圓環(huán)型Slider)
3.平面內(nèi)任意一點(diǎn)S(m,n)夷陋;--------(點(diǎn)擊的位置)
求:
1)點(diǎn)S到圓C的最短距離是否小于44;(限定點(diǎn)擊響應(yīng)的區(qū)域?yàn)閳A弧內(nèi)外44個(gè)點(diǎn)的區(qū)域)
2)線段SC與圓的交點(diǎn)T(xT,yT)胰锌;(thumb的位置骗绕,肯定在圓弧上)
3)線段ST的距離是否小于44;(限定點(diǎn)擊開始時(shí)的響應(yīng)區(qū)域?yàn)橐詔humb圓心资昧,半徑為44的圓以內(nèi))
2) 對(duì)于當(dāng)value=0%時(shí)酬土,滑塊不可以再逆時(shí)針滑動(dòng),當(dāng)value=100%時(shí)格带,滑塊不可以再順時(shí)針滑動(dòng)撤缴。
1. 平面內(nèi)一個(gè)圓C半徑為r刹枉,其圓心位于坐標(biāo)系原點(diǎn),即C(0,0)屈呕,圓弧上有一點(diǎn)T(x,y);
2. 坐標(biāo)系可分為第一微宝、二、三和四象限虎眨。
1)那么當(dāng)點(diǎn)T相對(duì)于起始點(diǎn)(0,-r)蟋软,順時(shí)針轉(zhuǎn)過的角度<60度時(shí),禁止移動(dòng)到第二嗽桩,三岳守,四象限;
2)當(dāng)點(diǎn)T相對(duì)于起始點(diǎn)(0,-r)涤躲,順時(shí)針轉(zhuǎn)過角度>300度時(shí)棺耍,禁止移動(dòng)到第一,二种樱,三象限蒙袍;