タイマーアプリを作るときに0から9までの数字を選択できる、かつ、0の前が9で9の次が0とループするPickerを作りました。
割とシンプルできれいに書けたので実際のアプリに使っているコードそのままですがサンプルとして残しておきます。
import SwiftUI
struct DigitPicker: View {
private let label: String
private let range: [Int]
@Binding private var selection: Int
@State private var innerSelection: Int = 0
private let loop = 100
init(_ label: String, _ range: [Int], _ selection: Binding<Int>) {
self.label = label
self.range = range
self._selection = selection
}
var body: some View {
Picker(label, selection: $innerSelection) {
ForEach(0..<(range.count * loop), id: \.self) { i in
let value = range[i % range.count]
Text("\(value)").tag(i)
}
}
.pickerStyle(.wheel)
.labelsHidden()
.frame(minWidth: 30, maxWidth: 30, minHeight: 50, maxHeight: 50)
.clipped()
.onAppear() {
innerSelection = selection + (range.count * loop / 2)
}
.onChange(of: innerSelection) {_, _ in
selection = innerSelection % range.count
}
}
}
簡単に解説しておくと
- loop回繰り返して0から9までの選択肢を用意
- 初期描画時に同じ値を表す真ん中の選択肢に選択を変更
- onChangeで選択肢から実際の数字(0から9)に変換
上記をすることで疑似的にループを実現しています。
疑似なのでひたすらピッカーを回し続ければ端でループは途切れますが、実用上は問題ないと割り切った作りになってます。
実際の動作は
ComposeTimerで確認できます。
無料アプリなので良かったらダウンロードして挙動を確かめてみてください。
https://apps.apple.com/jp/app/composetimer/id6740627031
アプリ起動後に右上のプラスから新規タイムラインを作成、タイムライン編集画面でパートのプラスから開くパート編集画面の項目「時間」でDigitPickerを6つ並べてパートの所要時間を入力できるようにしています。