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()
}
}
Related
I'm building a SwiftUI to-do app. You tap an Add button that pulls up a partial-height sheet where you can enter and save a new to-do. The Add sheet's input (TextField) should be focused when the sheet appears, so in order to keep things feeling fast and smooth, I'd like the sheet and the keyboard to animate onscreen together, at the same time. After much experimentation and Googling, I still can't figure out how to do it.
It seems like there are two paths to doing something like this:
(1) Autofocus the sheet
I can use #FocusState and .onAppear or .task inside the sheet to ensure the TextField is focused as soon as it comes up. It's straightforward functionally, but I can't find a permutation of it that will give me that single animation: it's sheet, then keyboard, presumably because those modifiers don't fire until the sheet is onscreen.
(2) Keyboard accessory view / toolbar
The .toolbar modifier seems tailor-made for a view of custom height that sticks to the keyboard--you lose the nice sheet animation but you gain the ability to have the view auto-size. However, .toolbar is designed to present controls alongside a TextField that itself isn't stuck to the keyboard. That is, the field has to be onscreen before the keyboard so it can receive focus...I don't know of a way to put the input itself inside the toolbar. Seems like chat apps have found a way to do this but I don't know what it is.
Any help would be much appreciated! Thanks!
Regarding option (1), I think there is no way to sync the animation. I decided to do it this way and don't worry about the delay between sheet and keyboard animation. Regarding option (2), you could try something like this:
struct ContentView: View {
#State var text = ""
#FocusState var isFocused: Bool
#FocusState var isFocusedInToolbar: Bool
var body: some View {
Button("Show Keyboard") {
isFocused = true
}
.opacity(isFocusedInToolbar ? 0 : 1)
TextField("Enter Text", text: $text) // Invisible Proxy TextField
.focused($isFocused)
.opacity(0)
.toolbar {
ToolbarItem(placement: .keyboard) {
HStack {
TextField("", text: $text) // Toolbar TextField
.textFieldStyle(.roundedBorder)
.focused($isFocusedInToolbar)
Button("Done") {
isFocused = false
isFocusedInToolbar = false
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
}
}
.onChange(of: isFocused) { newValue in
if newValue {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.05) {
isFocusedInToolbar = true
}
}
}
}
}
The trick is, that you need a TextField in your content that triggers the keyboard initally and then switch focus to the TextField in the toolbar. Otherwise you won't get the keyboard to show up.
When the user hits date picker in swiftUI, it opens up and shows calendar to choose date user may or may not choose date and user hits somewhere else in the view and date picker closes it self. I want to change date picker parent view border when user hits date picker and also when user tap somewhere else screen date picker closes and its parent view border does not changes.I want to handle the date picker parent view border color. when then date picker is closed or dismissed.
DatePicker("", selection: $datePicker, displayedComponents: .date)
.labelsHidden()
.padding(.trailing, 8)
.frame(alignment: .leading)
.colorMultiply(AppColors.textNavy100Color)
.accentColor(AppColors.textNavy100Color)
.onTapGesture {
print("date picker tapped")
if isFieldEditing == false{
isFieldEditing = true
}else {
isFieldEditing = false
}
}
I am facing out a strange behavior that really looks like a SwiftUI bug.
When I leave the app with a .sheet open and reopen it, all content from parent has an offset on tap. It is difficult to explain (and English is not my mother tongue) so here is a really simple example:
struct ContentView: View {
#State private var isOpen = false
var body: some View {
Button(action: {
isOpen.toggle()
}, label: {
Text("Open sheet")
.foregroundColor(.white)
.padding()
.background(.blue)
})
.sheet(isPresented: $isOpen, content: {
Text("Sheet content")
})
}
}
To reproduce the issue follow those steps:
Tap just below to the top border of blue button Open sheet: the sheet opens as expected.
When the sheet is open, close the app (go back to Springboard, cmd+shift+H on iOS Simulator).
Reopen the app. You're still on the sheet view.
Close the sheet. You're back on main view with blue button. Here is the bug:
Tap again on the top of blue button, right below the top border. Nothing happens. You have to click few pixels below. There is an offset that makes all tappable items on main view not aligned.
Does anyone have seen this bug also? Is there something I do wrong?
Other notices:
When closing the app from main view, the bug doesn't appear. And even when the bug is here and I close the app from main view and reopen, the bug disappears.
If I use a .fullScreenCover instead of .sheet, the bug doesn't appear.
It really looks like a bug with .sheets open.
EDIT:
I have tried two workarounds but both don't work:
Embed the Button in an external View.
Replace Button with only the Text and add .onTapGesture{ ... } modifier to toggle isOpen #State property.
EDIT 2:
After hours of tries I could find something interesting: if, in the sheet content, I add a button to dismiss the sheet, the bug doesn't appear anymore. But if I dismiss the sheet with finger (drag from top to bottom), it still appears.
Here is modified code:
struct ContentView: View {
#State private var isOpen = false
var body: some View {
Button(action: {
isOpen.toggle()
}, label: {
Text("Open sheet")
.foregroundColor(.white)
.padding()
.background(.blue)
})
.sheet(isPresented: $isOpen, content: {
SheetContent()
})
}
}
struct SheetContent: View {
#Environment(\.dismiss) var dismiss
var body: some View {
Button(action: { dismiss() }, label: {
Text("Dismiss sheet")
})
}
}
It looks like there is something with calling (or not) the #Environment(\.dismiss) var dismiss.
The current state is a bit better as few days ago as the bug only appears when user dismiss the sheet by dragging down. But there is still something wrong.
Is there a way to programmatically call dismiss() when sheet is closed by dragging down?
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))
}
}
I've added a Picker (SegmentedPickerStyle) to my project using SwiftUI as shown:
Picker(selection: $selectedType, label: Text("Type")) {
Text("Translation")
Text("Highlights")
}
.pickerStyle(SegmentedPickerStyle())
But for some reason, the result (both in canvas and the simulator) is a grey, disabled picker (please see screenshot attached).
What I try to achieve:
Does anyone has an idea what am I doing wrong?
Try as following
#State private var selectedType = 0
...
Picker(selection: $selectedType, label: Text("Type")) {
Text("Translation").tag(0)
Text("Highlights").tag(1)
}
.pickerStyle(SegmentedPickerStyle())
Your picker has 2 Text items, "Translation" & "Highlights". So your selection will be either of those Strings.
Create a #State variable to track when that selection changes and to show the new 'State'.
#State private var selectedType = "Translation"
...
Picker(selection: $selectedType, label: Text("Type")) {
Text("Translation")
Text("Highlights")
}
.pickerStyle(SegmentedPickerStyle())