iOS 圓環(huán)型滑塊(Circle Slider)

一、圓環(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 傳送門

  1. 重復(fù)滑動
圖二 重復(fù)滑動
  1. 限定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度時,禁止移動到第一,二,三象限;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,690評論 4 61
  • 三月,驚蜇。 一聲春雷,萬物復(fù)蘇了。南方有句農(nóng)諺:雷打驚蜇前,四十八天雨綿綿。前些天跟一個南方的朋友通...
    川江水閱讀 287評論 0 1
  • “快跑——!快跑——”尾音未落,這個仿佛要將嗓子撕裂般吼叫出來的聲音便在瞬間湮沒在了熊熊燃燒的大火之中。 少女的兩...
    ea3a431876df閱讀 472評論 0 1
  • 參加早起群已經(jīng)有六天了,之前就有早起的想法,但是嘗試了幾天后發(fā)現(xiàn)自己堅持不下來。主要是兩個原因,一個是沒有一個早起...
    楠牧閱讀 282評論 1 1
  • 前言 在上一節(jié)我們通過使用NumPy的數(shù)組分割成功的在我們的圖像上畫了一個綠色的方塊,但是如果我們想畫一個單一的線...
    樓上小宇閱讀 3,424評論 1 2

友情鏈接更多精彩內(nèi)容