Reputation: 615
Is it possible to use Apple's very own date picker and display just the year only?
This is my current code:
DatePicker("", selection: $cameraViewModel.age, displayedComponents: .date)
.datePickerStyle(CompactDatePickerStyle())
Of course the .displayedComponents
would allow me to alter the UI/elements however, there's no call for just the year.
I have searched Stackoverflow, found a thread, but the OP never followed up.
Upvotes: 7
Views: 6782
Reputation: 2893
I created this YearPicker
SwiftUI component
Observations of code: you need to create year, month, day, hour, minute, seconds, nanoseconds and time zone for .tag in Picker, correctly assign the initial value to select.
Any help to optimize is appreciated.
import SwiftUI
struct YearPicker: View {
@Binding var selectedDate: Date
let yearRange: ClosedRange<Int>
init(selection: Binding<Date>, yearRange: ClosedRange<Int> = 1900...2060) {
self._selectedDate = selection
self.yearRange = yearRange
// Ajustar el año seleccionado dentro del rango
let calendar = Calendar.current
let year = calendar.component(.year, from: selection.wrappedValue)
if !yearRange.contains(year) {
var adjustedYear = year
if year < yearRange.lowerBound {
adjustedYear = yearRange.lowerBound
} else if year > yearRange.upperBound {
adjustedYear = yearRange.upperBound
}
let originalComponents = calendar.dateComponents([.month, .day, .hour, .minute, .second, .nanosecond, .timeZone], from: selection.wrappedValue)
var components = DateComponents()
components.year = adjustedYear
components.month = originalComponents.month
components.day = originalComponents.day
components.hour = originalComponents.hour
components.minute = originalComponents.minute
components.second = originalComponents.second
components.nanosecond = originalComponents.nanosecond
components.timeZone = originalComponents.timeZone
self._selectedDate = Binding.constant(calendar.date(from: components)!)
}
}
var body: some View {
VStack {
Picker("Year", selection: $selectedDate) {
ForEach(yearRange, id: \.self) { year in
Text(displayYear(year: year))
.tag(self.dateFromYear(year))
}
}
}
}
private func displayYear(year: Int) -> String {
let numberFormatter: NumberFormatter = {
let nf = NumberFormatter()
nf.usesGroupingSeparator = false
return nf
}()
return numberFormatter.string(from: NSNumber(value: year)) ?? "\(year)"
}
private func dateFromYear(_ year: Int) -> Date {
let calendar = Calendar.current
let originalComponents = calendar.dateComponents([.month, .day, .hour, .minute, .second, .nanosecond, .timeZone], from: selectedDate)
var components = DateComponents()
components.year = year
components.month = originalComponents.month
components.day = originalComponents.day
components.hour = originalComponents.hour
components.minute = originalComponents.minute
components.second = originalComponents.second
components.nanosecond = originalComponents.nanosecond
components.timeZone = originalComponents.timeZone
return calendar.date(from: components)!
}
}
You can specific range value, default 1900...2060
#Preview {
struct PreviewWrapper: View {
@State var value: Date = Date()
var body: some View {
VStack {
YearPicker(selection: $value)
.onChange(of: value) { oldValue, newValue in
print("chanege:", value)
}
Text(value.description)
}
}
}
return PreviewWrapper()
}
You can see in action in short youtube YearPicker en SwiftUI
Upvotes: 0
Reputation: 54601
I don't think you can do this with a DatePicker
- it's for selecting a Date
and a year is just a simple Int
.
Displaying a year only can be achieved with a standard Picker
(although the appearance may differ):
struct ContentView: View {
@State var selection = Date()
var body: some View {
Picker("", selection: $selection) {
ForEach(2000...2020, id: \.self) {
Text(String($0))
}
}
.pickerStyle(InlinePickerStyle())
}
}
Upvotes: 7