post Image
UISliderのUXをトコトン追究して改善してみる

UISliderって・・・?

UISliderはその名の通りスライダーコントロール機能を提供するUIKit標準のUIパーツで、
バー(track)とつまみ(thumb)で構成された値を調節する際などに便利なUIです:sparkles:

slider.png

他のUIViewやUIButtonなどに比べると登場頻度は少ないかもしれませんが、
UISliderの特性を知っておいて損はないと思います:point_up:

本稿では標準のUISliderをサンプルコードを交えながらカスタムし、
UXや使い心地を向上してみたいと思います:sunglasses:

UISliderはthumbのドラッグのみで調節可能

UISliderを用いた値の調節は白い丸のつまみ部分(thumbと呼びます)をドラッグして、
左右に動かすことで直感的な調節操作を実現しています。

UISliderはUIControlクラスを継承しており、
addTarget()することで様々なコントロールイベント(UIControlEvents)をフックすることが可能です。
UISliderで最も使用する頻度が高いUIControlEventsは、.valueChangedでしょう。
下記は、UISliderのvalueの変化をフックするサンプルコードです。
実行してつまみをドラッグすると値が断続的に取れているかと思います。

class ViewController: UIViewController {
    @IBOutlet weak var slider: UISlider! // InterfaceBuilderで定義

    override func viewDidLoad() {
        super.viewDidLoad()

        slider.addTarget(self, action: #selector(sliderDidChangeValue(_:)), for: .valueChanged)
    }

    @objc func sliderDidChangeValue(_ sender: UISlider) { // @IBActionでも可
        print(sender.value) // 0.0
    }
}

UISliderの個人的にイケてないと感じるポイント

上で説明したように、デフォルトのUISliderは、
thumbをドラッグすることで値を調節することができます。
裏を返せば、thumbをドラッグしなければ値を調節することができません

thumbをつまもうとしてドラッグしたら、空振りして失敗してしまう

皆さんも一度はこのような経験をされているのではないでしょうか?
何個かの改善方法とともにUISliderのユーザビリティを磨きこんでいきます:sparkles:

改善① UISliderのthumb以外をタップやドラッグしても調節可能にする

デフォルトでは、UISliderのタップ領域 = thumbのタップ領域です。
では、どのようなロジックでスライダーの調節開始を判定しているのでしょうか。

UISliderの親クラスであるUIControlのDocumentを見ると、
beginTracking(_:with:)というメソッドが用意されています。

func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool

このメソッドによって、スライダーの調節を開始するべきか判定しています。
おおよそ、デフォルトの実装はtouchされた座標がthumbの座標内にあるかというのを見て、
調節を開始させるかどうか判定しているのだと思われます。

API提供されてる範囲で実装してみるとこんな感じでしょうか。

func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
    // thumbのrectを算出する
    let thumbRect = self.thumbRect(
        forBounds: bounds,
        trackRect: trackRect(forBounds: bounds), // バー(track)のrect
        value: value
    )

    // tapした座標
    let tapPoint = touch.location(in: self)

    // tapした座標がthumbの矩形内に含まれていれば調節開始する
    return thumbRect.contains(tapPoint)
}

では、このメソッドを無条件にtrueを返却するようにoverrideするとどうなるでしょうか。
どんなtouchでもtrackingを開始するようになるため、
つまみ部分以外の領域を選択しても調節が可能となります。

つまみ(thumb)以外をタップしても調節可能なスライダー
class TappableSlider: UISlider {
    override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        return true // どんなtouchでもスライダー調節を行う
    }
}

実際に動かしてみるとこんな感じです!
つまみがない部分をタップしたりドラッグしたりできるようになっているのがわかるかと思います。

TappableSlider.gif

改善② UISliderのタップ領域を広げる

①で説明したthumb以外をタップしても調節可能にする方法は、
UISliderの領域内であればどこでも選択可能となりました。

しかし、UISliderのbounds外をタップしても反応してくれません。
たとえば、こんな感じの目盛り付きのスライダーUIがあるとします。
image.png
黄色い部分はUISliderのbounds領域です。

デフォルトではつまみの選択のみ、スライダーを動かすことができました。
改善①によって、黄色い部分のどこを選択してもスライダーが動くようになりました。
しかし、1-5の目盛りラベルを選択してもスライダーは動きません。
これを反応できるようにタップ領域を拡大してみましょう。

UISliderでタップ領域を決定しているメソッドは、UIControlのpoint(inside:with:)です。
つまり、このメソッドでtrueが返却された後にbeginTracking(_:with:)が呼ばれます

func point(inside point: CGPoint, with event: UIEvent?) -> Bool

こちらのメソッドもDocumentを見る限り、
おおよそ、デフォルトの実装は、pointに入ってくる値が自身のbounds内にあるかどうかでしょう。

つまり、こんな感じだと想定されます。

func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    return bounds.contains(point) // pointがbounds内にあるかどうか
}

ラベル部分は自身のbounds外となるため、
そこを選択してもbeginTrackingが呼ばれませんでした。

では、ラベル部分も選択可能にするために、
UISliderのboundsより20px下まで判定を可能にしてみましょう。

下に20px広くタップが可能なスライダー
class WideTappableSlider: TappableSlider {
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        var wideBounds = bounds
        wideBounds.size.height += 20.0 // boundsを20.0px分下に拡張
        return wideBounds.contains(point) // pointがwideBounds内にあるかどうか
    }
}

これでどうでしょうか。
目盛り部分をタップするとその位置にスライダーを動かすことができるようになりました:tada:
slider2.gif

最後に

最後までお読みいただきありがとうございます:bow:
いかがだったでしょうか?

UISliderのUX改善について2つの方法をまとめてみました。
どちらの方法も親クラスのUIControlのメソッドをoverrideしているので、
UISlider以外のUIKitにも応用が可能だったりします。

他にもUISliderのUX改善法を知っている方がいましたら、
コメントしていただけると幸いです!

こうした細かいチューニングでアプリのUXをどんどん磨いていきましょう。

それでは:raised_hand:

参考リンク


『 Swift 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。