Skip to content

Instantly share code, notes, and snippets.

@kafran
Forked from mattyoung/TemperatureSliderDemo.swift
Created January 24, 2023 11:18
Show Gist options
  • Save kafran/d1af079b5b612df41543f54af7e789a2 to your computer and use it in GitHub Desktop.
Save kafran/d1af079b5b612df41543f54af7e789a2 to your computer and use it in GitHub Desktop.
import SwiftUI
// pre-create one instance of MeasurementFormatter for our format needs
// re-use as needed
extension MeasurementFormatter {
static private let formatter: MeasurementFormatter = {
let formatter = MeasurementFormatter()
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.minimumFractionDigits = 2
numberFormatter.maximumFractionDigits = 2
numberFormatter.roundingMode = .halfUp
formatter.numberFormatter = numberFormatter
return formatter
}()
static func formatter(unitOptions: MeasurementFormatter.UnitOptions = []) -> MeasurementFormatter {
Self.formatter.unitOptions = unitOptions
return Self.formatter
}
}
/// A slider to input any kind of Measurement value in any kind of Dimension unit such as UnitTemperature, UnitLength, UnitMass
/// within min, max range, optinal step value
struct DimensionSlider<UnitType: Dimension>: View {
@Binding var value: Measurement<UnitType>
let unit: UnitType
let min, max: Measurement<UnitType>
let step: Double // slider step size in the specified unit
init(value: Binding<Measurement<UnitType>>, unit: UnitType, min: Measurement<UnitType>, max: Measurement<UnitType>, step: Double = 0.5) {
self._value = value
self.unit = unit
self.min = min.converted(to: unit)
self.max = max.converted(to: unit)
self.step = step
}
var body: some View {
VStack {
// show value in specified unit
Text(MeasurementFormatter.formatter(unitOptions: .providedUnit).string(from: self.value.converted(to: unit)))
Slider(value: Binding<Double>(get: { self.value.converted(to: self.unit).value }, set: { self.value = Measurement(value: $0, unit: self.unit)}),
in: self.min.value...self.max.value,
step: self.step,
minimumValueLabel: Text("\(self.min.value, specifier: "%.2f")"), // show just the number without unit symbol
maximumValueLabel: Text("\(self.max.value, specifier: "%.2f")")) {
Text("Er, what's this for?")
}
}
}
}
private struct DisplayView<UnitType: Unit>: View {
let label: String
let value: Measurement<UnitType>
var body: some View {
HStack {
Text(label)
.font(.title)
Text(MeasurementFormatter.formatter().string(from: value))
.font(Font.title.monospacedDigit())
.foregroundColor(.green)
}
.padding()
.background(Color.gray)
.cornerRadius(10.0)
.padding(.vertical)
}
}
struct TemperatureSliderDemo: View {
// Using Measurement, you can specify temperature in any unit
@State private var temperature = Measurement(value: 273.15, unit: UnitTemperature.kelvin)
let minTemperature = Measurement(value: -100, unit: UnitTemperature.celsius)
let maxTemperature = Measurement(value: 300, unit: UnitTemperature.fahrenheit)
@State private var weight = Measurement(value: 26.7, unit: UnitMass.pounds)
let minWeight = Measurement(value: 2, unit: UnitMass.ounces)
let maxWeight = Measurement(value: 1000, unit: UnitMass.kilograms)
@State private var distance = Measurement(value: 368.98, unit: UnitLength.miles)
let minDistance = Measurement(value: 0, unit: UnitLength.meters)
let maxDistance = Measurement(value: 19000, unit: UnitLength.kilometers)
var body: some View {
VStack {
Group {
DisplayView(label: "Temperature", value: temperature)
DimensionSlider(value: $temperature, unit: UnitTemperature.fahrenheit, min: minTemperature, max: maxTemperature)
.padding(.horizontal)
DimensionSlider(value: $temperature, unit: UnitTemperature.celsius, min: minTemperature, max: maxTemperature)
.padding(.horizontal)
DimensionSlider(value: $temperature, unit: UnitTemperature.kelvin, min: minTemperature, max: maxTemperature)
.padding(.horizontal)
}
Spacer()
Group {
DisplayView(label: "Weight", value: weight)
DimensionSlider(value: $weight, unit: UnitMass.grams, min: minWeight, max: maxWeight, step: 10)
.padding(.horizontal)
DimensionSlider(value: $weight, unit: UnitMass.decigrams, min: minWeight, max: maxWeight, step: 100)
.padding(.horizontal)
DimensionSlider(value: $weight, unit: UnitMass.milligrams, min: minWeight, max: maxWeight, step: 30)
.padding(.horizontal)
}
Spacer()
Group {
DisplayView(label: "Distance", value: distance)
DimensionSlider(value: $distance, unit: UnitLength.inches, min: minDistance, max: maxDistance, step: 10)
.padding(.horizontal)
DimensionSlider(value: $distance, unit: UnitLength.fathoms, min: minDistance, max: maxDistance, step: 100)
.padding(.horizontal)
}
}
}
}
struct TemperatureSliderDemo_Previews: PreviewProvider {
static var previews: some View {
TemperatureSliderDemo()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment