Skip to content

Instantly share code, notes, and snippets.

@d-date
Created October 8, 2024 01:58
Show Gist options
  • Save d-date/4716407bad708cf84d03a8b87e3e8f0e to your computer and use it in GitHub Desktop.
Save d-date/4716407bad708cf84d03a8b87e3e8f0e to your computer and use it in GitHub Desktop.
import SwiftUI
public struct DatePickerTextField: View {
/// Config
var components: DatePicker.Components
@Binding var date: Date
var formattedString: (Date) -> String
/// View properties
@State private var viewID: String = UUID().uuidString
@FocusState private var isActive
public init(
components: DatePicker.Components = [.date, .hourAndMinute],
date: Binding<Date>,
formattedString: @escaping (Date) -> String
) {
self.components = components
self._date = date
self.formattedString = formattedString
}
public var body: some View {
TextField(viewID, text: .constant(formattedString(date)))
.focused($isActive)
.toolbar {
ToolbarItem(placement: .keyboard) {
Button {
isActive = true
} label: {
Text("Done", bundle: .module)
}
.tint(Color.primary)
.frame(maxWidth: .infinity, alignment: .trailing)
}
}
.overlay {
AddInputViewToPicker(id: viewID) {
/// SwiftUI Date Picker
DatePicker("", selection: $date, displayedComponents: components)
.labelsHidden()
.datePickerStyle(.wheel)
}
.onTapGesture {
isActive = true
}
}
}
}
fileprivate struct AddInputViewToPicker<Content: View>: UIViewRepresentable {
var id: String
@ViewBuilder var content: Content
func makeUIView(context: Context) -> some UIView {
let view = UIView()
view.backgroundColor = .clear
Task { @MainActor in
if let window = view.window, let textField = window.allSubViews(
ofType: UITextField.self).first(where: { $0.placeholder == id }) {
textField.tintColor = .clear
/// Converting SwiftUI View to UIKit View
let hostView = UIHostingController(rootView: content).view!
hostView.backgroundColor = .clear
hostView.frame.size = hostView.intrinsicContentSize
/// Adding as InputView
textField.inputView = hostView
textField.reloadInputViews()
}
}
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) { }
}
fileprivate extension UIView {
func allSubViews<T: UIView>(ofType type: T.Type) -> [T] {
var resultViews = subviews.compactMap({ $0 as? T })
for view in subviews {
resultViews.append(contentsOf: view.allSubViews(ofType: type))
}
return resultViews
}
}
#if DEBUG
struct ContentView: View {
/// View properties
@State private var date: Date = .now
var body: some View {
NavigationStack {
DatePickerTextField(date: $date) { date in
return date.formatted()
}
.navigationTitle("Date Picker TextField")
}
}
}
#endif
#Preview {
ContentView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment