Created
October 8, 2024 01:58
-
-
Save d-date/4716407bad708cf84d03a8b87e3e8f0e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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