I'm using a DatePickerinside a SwiftUI List. I'm only interested in hours and minutes and therefore don't need the newly introduced calendar view.
How can I prevent the popup that appears once a user taps on the time (8:30 AM)? It would be ideal if it can be edited inline like in the iOS calendar app.
Here's how I'm creating the DatePicker:
DatePicker("Send motivation at", selection: $settings.dailyMotivationReminder, displayedComponents: .hourAndMinute)
.datePickerStyle(DefaultDatePickerStyle())
.font(.system(.body, design: .serif))
.disabled(!settings.isDailyMotivationEnabled)
.opacity(settings.isDailyMotivationEnabled ? 1.0 : 0.4)
You can use GraphicalDatePickerStyle:
List {
HStack {
Text("Send motivation at")
DatePicker("", selection: $settings.dailyMotivationReminder, displayedComponents: .hourAndMinute)
.datePickerStyle(GraphicalDatePickerStyle())
.font(.system(.body, design: .serif))
}
}
Related
I'm trying to make an mobile app for a reservation system. Users can reserve the product from different timezones. So when a user from NY city tries to reserve a product from Paris, I need to be sure user selected the time in Europe/Paris timezone. Currently swiftUI datepicker uses the system current timezone which is of course GMT-5 so when they select 13:00 the Date() object sets itself to 18:00 UTC, but I need him/her to be select in GMT+1 so when they select 13:00 I should set the Date() object to 12:00 UTC. I have tried to use environment value for timezone but it changes the timezone application wide, I just need to change the timezone of datepicker not all application.
Here are the solutions I've tried to change timezone
DatePicker("", selection: $viewModel.tripRequest.date, displayedComponents: .hourAndMinute)
.labelsHidden()
.padding(.horizontal)
.font(.custom("Gilroy-Regular", size: 36))
.cornerRadius(15)
.environment(\.timeZone, TimeZone(secondsFromGMT: 3600)!)
I've also tried to use introspect with no luck
DatePicker("", selection: $viewModel.tripRequest.date, displayedComponents: .hourAndMinute)
.labelsHidden()
.padding(.horizontal)
.font(.custom("Gilroy-Regular", size: 36))
.cornerRadius(15)
.introspectDatePicker { datePicker in
datePicker.timeZone = TimeZone(secondsFromGMT: 3600)
}
SwiftUI's DatePicker uses the device's Timezone by default.
You can specify a Timezone using .environment(\.timeZone, TimeZone(identifier: "Specific identifier")!)
But Date is in UTC so if the user picks a date in one timezone when viewed in another timezone it will be adjusted. You can't change the timezone for Date.
import SwiftUI
struct WorldTimeView: View {
#State private var date: Date = .init()
var body: some View {
VStack{
DatePicker("US", selection: $date, displayedComponents: .hourAndMinute)
//US Date Picker
.environment(\.timeZone, TimeZone(identifier: "America/New_York")!)
DatePicker("Paris", selection: $date, displayedComponents: .hourAndMinute)
//Paris Date Picker
.environment(\.timeZone, TimeZone(abbreviation: "CET")!)
//User/Device Date Picker
DatePicker("Local", selection: $date, displayedComponents: .hourAndMinute)
}
}
}
struct WorldTimeView_Previews: PreviewProvider {
static var previews: some View {
WorldTimeView()
}
}
Im using the native DatePicker in swiftUI presented through a sheet. The date picker it self is of graphical style. When the sheet is presented I can scroll through months but I cannot make a selection. To make a selection I have to constantly press on the date for 5-6 seconds. But if I use a wheel style everything works as expected. Im not sure if this is an iOS bug or something I am missing. Note: code works on preview_provider but not on actual device.
#State var showCalendar:Bool = false
#State var selectedDate:Date = Date()
.sheet(isPresented: $showCalendar){
VStack{
DatePicker("", selection: $selectedDate, displayedComponents: [.date])
.datePickerStyle(.graphical)
Spacer()
}
}
I have the following button in a custom view that I reuse in multiple places
Button(action: { selectedDate = date }) {
VStack {
Text(day.shortName)
.font(.caption2)
.foregroundColor(isSelectedDate ? .white : .primary)
.frame(maxWidth: .infinity)
Spacer().frame(height: 7)
Text("\(date.dayOfMonth)")
.bold()
.foregroundColor(isSelectedDate ? .white : .primary)
.frame(maxWidth: .infinity)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.purple.brightness(isSelectedDate ? 0 : 0.6))
.clipped()
}.disabled(isInPast)
Dates in the past supposed to be disabled, and I confirmed that they are actually disabled as expected; however, the disabled styling looks different in multiple screens although it's the exact same view being used.
What could cause the disable state to not be styled accordingly in some screens?
In both screenshots dates from 25-29 are disabled
In both usages I simply add the view to a VStack
var body: some View {
VStack {
WeekView(selectedDate: $booking.selectedDate).padding()
var body: some View {
VStack(spacing: 0) {
WeekView(selectedDate: $selectedDate)
.padding(.horizontal)
.padding(.bottom)
Don't rely on primary color. Use a custom color and use isInPast to make an opacity.
Figured it out, the parent in one of the screens had .buttonStyle(.plain) which makes the disabled styling work as expected. So I just dded that to the component itself to make sure the disabled styling is always in place
For some reason Apple decided to drop Label support for Pickers
(tested in iOS15 and iOS16)
For example:
Picker(selection: $gender,
label:
"Select your gender"
, content: {
Text(Gender.male.rawValue).tag(Gender.male)
Text(Gender.female.rawValue).tag(Gender.female)
Text(Gender.nobinary.rawValue).tag(Gender.nobinary)
}).pickerStyle(.automatic)
.font(.largeTitle)
.accentColor(.white)
ignores the label view.
So howto solve that?
To add a Label View out of the box without custom View one has to use Picker in Menu View embedded.
Now one can use modifier on the Menu Label Views and even use logic for the selected text.
Menu {
Picker(selection: $gender,
label: EmptyView(),
content: {
Text(Gender.male.rawValue).tag(Gender.male)
Text(Gender.female.rawValue).tag(Gender.female)
Text(Gender.nobinary.rawValue).tag(Gender.nobinary)
}).pickerStyle(.automatic)
.accentColor(.white)
} label: {
Text(gender == .unselected ? "Select your gender" : gender.rawValue)
.font(.title3)
.frame(maxWidth: .infinity)
.frame(height: 55)
.background(.white)
.cornerRadius(10)
.accentColor(.pink)
}
I have emoji inside Text view (SwiftUI) and it doesn't vertically align with the rest of the text.
Code I have:
var body: some View {
VStack {
Text("PUT THE BULLLS EYE 🎯 AS CLOSE AS YOU CAN TO THE")
.bold()
.kerning(2.0)
.multilineTextAlignment(.center)
.lineSpacing(4.0)
.font(.system(size: 13, weight: .medium, design: .default))
Text("89")
HStack {
Text("1")
Slider(value: Binding.constant(50), in: 1.0...100.0)
Text("100")
}
Button(action: {}) {
Text("Hit Me!")
}
}
Notice in the screenshot target emoji 🎯 sits below the text and I want to align with the rest of the text in the same line. Any ideas?
You can use + to attach Text components. Then, you can change the baseline of one of the elements:
Group {
Text("PUT THE BULLLS EYE ").bold().kerning(2.0)
+ Text("🎯").baselineOffset(3) + Text(" AS CLOSE AS YOU CAN TO THE").bold().kerning(2.0)
}
.multilineTextAlignment(.center)
.lineSpacing(4.0)
.font(.system(size: 13, weight: .medium, design: .default))
The version I have above is fragile since it depends on a magic number (3) for the current font size, but you could do some work to calculate what it would be for other sizes.