TextField & Slider 値の同期【SwiftUI】

TextFieldの値とSliderのバーを同期させる方法

自作のBinding

import SwiftUI

struct SliderTextFieldSyncView: View {
    @State private var value: Double = 50.0  // 共通の状態

    var body: some View {
        VStack(spacing: 20) {
            Slider(value: $value, in: 0...1000, step: 1)
            
            // TextFieldではDoubleをStringに変換して表示・編集
            TextField("数値を入力", text: Binding(
                get: {
                    String(format: "%.0f", value)
                },
                set: { newValue in
                    if let doubleValue = Double(newValue) {
                        value = min(max(doubleValue, 0), 1000)  // 範囲外防止
                    }
                    else {
                        // 無効な入力に対する対応(例:無視、前の値に戻す、警告表示など)

                    }
                }
            ))
            .keyboardType(.numberPad)
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .frame(width: 100)
        }
        .padding()
    }
}

#Preview {
    SliderTextFieldSyncView()
}

SwiftUIのTextFieldはBinding<String>を受け取る。一方で、Sliderで扱う値はDouble型になります。したがって、そのまま$valueを渡すことができないため、Double←→Stringの変換を含む、カスタムバインディングを作成する必要がある。

Binding(
    get: {
        String(format: "%.0f", value)
    },
    set: { newValue in
        if let doubleValue = Double(newValue) {
            value = min(max(doubleValue, 0), 1000)
        }
    }
)

getに表示するときの処理を書き、setに入力する際の処理を記述します。

NumberFormatterを利用

import SwiftUI

struct SliderTextFieldSyncView: View {
    @State private var value: Double = 50.0

    // NumberFormatterを定義(ローカライズ対応)
    private var numberFormatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal       // 桁区切りや小数点をローカル形式で表示
        formatter.maximumFractionDigits = 0    // 小数点以下を表示しない
        formatter.minimum = 0
        formatter.maximum = 1000
        return formatter
    }

    var body: some View {
        VStack(spacing: 20) {
            Slider(value: $value, in: 0...1000, step: 1)

            TextField("数値を入力", value: $value, formatter: numberFormatter)
                .keyboardType(.numberPad)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .frame(width: 100)
        }
        .padding()
    }
}

#Preview {
    SliderTextFieldSyncView()
}
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次