[Swift]つまみが２つあるsliderをRangeUISliderで実装してみた


## はじめに
swiftでsliderを使用するとなると、UISliderが一般的ですよね。
![ダウンロード (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112697/e3a40846-5aef-344b-b0ce-dc25e0c3e50f.png)


ただ、つまみを２つにしたい（範囲を選択したいなど）場合はUISliderでは難しいのが現実だと思います。

そこでRangeUISliderというライブラリを使い、実現できたので記載していきます。


## ライブラリ

https://github.com/chicio/RangeUISlider

podでインポートします。

```ruby:Podfile
pod 'RangeUISlider', '~> 3.0'

```

※SwiftPackageManagerでも入れることができます

## イメージ

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112697/b2d2455f-b168-06d1-ea3d-c2e265a18759.gif" width="200">


今回は時間間隔を取得するケースです。

左のつまみ調整で開始時間、右のつまみ調整で終了時間がLabelに反映されます。


## ソースコード

```swift:RangeUISliderViewController.swift
import UIKit
import RangeUISlider

final class RangeUISliderViewController: UIViewController {

    @IBOutlet weak var startTimeLabel: UILabel!
    @IBOutlet weak var endTimeLabel: UILabel!
    
    @IBOutlet weak var rangeUISlider: RangeUISlider! {
        didSet {
            rangeUISlider.delegate = self
        }
    }
    

    override func viewDidLoad() {
        setUpView()
    }
}

// MARK: - SetUpRangeUISlider
extension RangeUISliderViewController: RangeUISliderDelegate {
    func rangeIsChanging(minValueSelected: CGFloat, maxValueSelected: CGFloat, slider: RangeUISlider) {
        startTimeLabel.text = SliderCalculation.transformTimeString(value: minValueSelected)
        endTimeLabel.text = SliderCalculation.transformTimeString(value: maxValueSelected)
    }

    func setUpView() {
        rangeUISlider.leftKnobColor = .blue
        rangeUISlider.rightKnobColor = .blue
        rangeUISlider.rangeSelectedColor = .blue
        rangeUISlider.rangeNotSelectedColor = UIColor.gray
        rangeUISlider.leftKnobWidth = 20
        rangeUISlider.leftKnobHeight = 20
        rangeUISlider.leftKnobCorners = 10
        rangeUISlider.rightKnobWidth = 20
        rangeUISlider.rightKnobHeight = 20
        rangeUISlider.rightKnobCorners = 10
        rangeUISlider.barHeight = 5
        rangeUISlider.scaleMinValue = 0
        rangeUISlider.scaleMaxValue = 100
        rangeUISlider.defaultValueLeftKnob = 0
        rangeUISlider.defaultValueRightKnob = 100
        rangeUISlider.scaleMinValue = 0
        rangeUISlider.scaleMaxValue = 96
        rangeUISlider.stepIncrement = 1
    }
}
```

まずはViewを配置して、@IBOutletで繋ぎます。

その際、TypeをUIViewではなくRangeUISliderにするのが肝です。

![スクリーンショット 2022-08-03 15.59.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112697/edc11db4-d37e-ff70-8fce-d08ad98ab87f.png)


あとは開始時間と終了時間のLabelを追加します。


値はどうやって受けとっているかというと・・

```swift:   
func rangeIsChanging(minValueSelected: CGFloat, maxValueSelected: CGFloat, slider: RangeUISlider) {
        startTimeLabel.text = SliderCalculation.transformTimeString(value: minValueSelected)
        endTimeLabel.text = SliderCalculation.transformTimeString(value: maxValueSelected)
    }

```

上記メソッドで、minValueSelectedが最小の値、maxValueSelectedで最大の値をCGFloatで受け取れます。

そして、計算用クラスのメソッドでStringに変換しています。

```swift:SliderCalculation.swift
import UIKit

final class SliderCalculation {
     // CGFloatで渡ってきた値を時間に変換して返す
    static func transformTimeString(value: CGFloat) -> String {
        let hour = floor(value / 4)
        let minute = value.truncatingRemainder(dividingBy: 4) * 15
        // 0埋めする
        var formatHour = String(format: "%02.0f", hour)
        var formatMinute = String(format: "%02.0f", minute)

        return "\(formatHour):\(formatMinute)"
    }
}
```

全体の範囲が２４時間で、１５分刻みの値を取得する計算です。

セットアップ時にデフォルトの最小・最大値を決定しています。
```swift:RangeUISliderViewController.swift
 
rangeUISlider.scaleMaxValue = 96
rangeUISlider.stepIncrement = 1

```


時間取得の場合は単純に4で割り、分取得の場合は4で割った余りに15をかけています。
その後に0埋めして、Stringとして返せば終わり。
```swift:  
 let hour = floor(value / 4)
 let minute = value.truncatingRemainder(dividingBy: 4) * 15

//valueが５０の場合・・・
//12:30となる
```

## おわりに　

ソースコードはGitHubにのせていますので、サクッと挙動確認したい場合はそちらから↓

https://github.com/taro-ken/RangeUISlider-Sample

計算の箇所はもっとスッキリとした書き方がありそうなので、分かる方はご教授願います・・！