@@ -11,8 +11,8 @@ import UIKit
1111public struct CurrencyTextField : UIViewRepresentable {
1212
1313 @Binding var value : Double ?
14-
15- public typealias UIViewType = UITextField
14+ private var isResponder : Binding < Bool > ?
15+ private var tag : Int
1616
1717 private var placeholder : String
1818
@@ -31,6 +31,7 @@ public struct CurrencyTextField: UIViewRepresentable {
3131 private var isUserInteractionEnabled : Bool
3232 private var clearsOnBeginEditing : Bool
3333
34+ private var onReturn : ( ) -> Void
3435 private var onEditingChanged : ( Bool ) -> Void
3536
3637 @Environment ( \. layoutDirection) private var layoutDirection : LayoutDirection
@@ -39,6 +40,9 @@ public struct CurrencyTextField: UIViewRepresentable {
3940 public init (
4041 _ placeholder: String = " " ,
4142 value: Binding < Double ? > ,
43+ isResponder: Binding < Bool > ? = nil ,
44+ tag: Int = 0 ,
45+
4246 font: UIFont ? = nil ,
4347 foregroundColor: UIColor ? = nil ,
4448 accentColor: UIColor ? = nil ,
@@ -51,10 +55,14 @@ public struct CurrencyTextField: UIViewRepresentable {
5155 isSecure: Bool = false ,
5256 isUserInteractionEnabled: Bool = true ,
5357 clearsOnBeginEditing: Bool = false ,
58+ onReturn: @escaping ( ) -> Void = { } ,
5459 onEditingChanged: @escaping ( Bool ) -> Void = { _ in }
5560 ) {
5661 self . _value = value
5762 self . placeholder = placeholder
63+ self . isResponder = isResponder
64+ self . tag = tag
65+
5866 self . font = font
5967 self . foregroundColor = foregroundColor
6068 self . accentColor = accentColor
@@ -67,24 +75,21 @@ public struct CurrencyTextField: UIViewRepresentable {
6775 self . isSecure = isSecure
6876 self . isUserInteractionEnabled = isUserInteractionEnabled
6977 self . clearsOnBeginEditing = clearsOnBeginEditing
78+ self . onReturn = onReturn
7079 self . onEditingChanged = onEditingChanged
7180 }
7281
73- public func makeCoordinator( ) -> CurrencyTextField . Coordinator {
74- Coordinator ( value: $value) { flag in
75- self . onEditingChanged ( flag)
76- }
77- }
78-
7982 public func makeUIView( context: UIViewRepresentableContext < CurrencyTextField > ) -> UITextField {
8083
8184 let textField = UITextField ( )
8285 textField. delegate = context. coordinator
83- textField. addDoneButtonOnKeyboard ( )
8486
8587 textField. addTarget ( context. coordinator, action: #selector( context. coordinator. textFieldEditingDidBegin ( _: ) ) , for: . editingDidBegin)
8688 textField. addTarget ( context. coordinator, action: #selector( context. coordinator. textFieldEditingDidEnd ( _: ) ) , for: . editingDidEnd)
8789
90+ // tag
91+ textField. tag = self . tag
92+
8893 // font
8994 if let f = context. environment. font {
9095 switch f {
@@ -156,14 +161,33 @@ public struct CurrencyTextField: UIViewRepresentable {
156161 return textField
157162 }
158163
164+ public func makeCoordinator( ) -> CurrencyTextField . Coordinator {
165+ Coordinator ( value: $value, isResponder: self . isResponder, onReturn: self . onReturn) { flag in
166+ self . onEditingChanged ( flag)
167+ }
168+ }
169+
159170 public func updateUIView( _ textField: UITextField , context: UIViewRepresentableContext < CurrencyTextField > ) {
171+
172+ // value
160173 if self . value != context. coordinator. internalValue {
161174 if self . value == nil {
162175 textField. text = nil
163176 } else {
164177 textField. text = Formatter . currency. string ( from: NSNumber ( value: self . value!) )
165178 }
166179 }
180+
181+ // set first responder ONCE
182+ // other times, let textfield handle it
183+ if self . isResponder? . wrappedValue == true && !textField. isFirstResponder && !context. coordinator. didBecomeFirstResponder {
184+ textField. becomeFirstResponder ( )
185+ context. coordinator. didBecomeFirstResponder = true
186+ }
187+
188+ // to dismiss, use dismissKeyboard()
189+ // don't uiView.resignFirstResponder()
190+ // otherwise many uibugs when using NavigationView
167191 }
168192
169193 public static func dismantleUIView( _ uiView: UITextField , coordinator: CurrencyTextField . Coordinator ) {
@@ -172,13 +196,18 @@ public struct CurrencyTextField: UIViewRepresentable {
172196
173197 public class Coordinator : NSObject , UITextFieldDelegate {
174198 @Binding var value : Double ?
199+ private var isResponder : Binding < Bool > ?
200+ private var onReturn : ( ) -> ( )
175201 var internalValue : Double ?
176202 var onEditingChanged : ( Bool ) -> ( )
203+ var didBecomeFirstResponder = false
177204
178- init ( value: Binding < Double ? > , onEditingChanged: @escaping ( Bool ) -> Void = { _ in } ) {
205+ init ( value: Binding < Double ? > , isResponder : Binding < Bool > ? , onReturn : @escaping ( ) -> Void = { } , onEditingChanged: @escaping ( Bool ) -> Void = { _ in } ) {
179206 print ( " coordinator init " )
180207 _value = value
181208 internalValue = value. wrappedValue
209+ self . isResponder = isResponder
210+ self . onReturn = onReturn
182211 self . onEditingChanged = onEditingChanged
183212 }
184213
@@ -251,17 +280,33 @@ public struct CurrencyTextField: UIViewRepresentable {
251280 return true
252281 }
253282
283+ public func textFieldDidBeginEditing( _ textField: UITextField ) {
284+ DispatchQueue . main. async {
285+ self . isResponder? . wrappedValue = true
286+ }
287+ }
288+
289+ public func textFieldDidEndEditing( _ textField: UITextField ) {
290+ DispatchQueue . main. async {
291+ self . isResponder? . wrappedValue = false
292+ }
293+ }
294+
254295 @objc func textFieldEditingDidBegin( _ textField: UITextField ) {
255296 onEditingChanged ( true )
256297 }
257298 @objc func textFieldEditingDidEnd( _ textField: UITextField ) {
258299 onEditingChanged ( false )
259300 }
260301
261- public func textFieldDidEndEditing( _ textField: UITextField , reason: UITextField . DidEndEditingReason ) {
262- if reason == . committed {
302+ public func textFieldShouldReturn( _ textField: UITextField ) -> Bool {
303+ if let nextField = textField. superview? . superview? . viewWithTag ( textField. tag + 1 ) as? UITextField {
304+ nextField. becomeFirstResponder ( )
305+ } else {
263306 textField. resignFirstResponder ( )
264307 }
308+ self . onReturn ( )
309+ return true
265310 }
266311 }
267312}
@@ -350,36 +395,3 @@ fileprivate extension NumberFormatter {
350395 self . numberStyle = numberStyle
351396 }
352397}
353-
354- fileprivate extension UITextField {
355-
356- @IBInspectable var doneAccessory : Bool {
357- get {
358- return self . doneAccessory
359- }
360- set ( hasDone) {
361- if hasDone{
362- addDoneButtonOnKeyboard ( )
363- }
364- }
365- }
366-
367- func addDoneButtonOnKeyboard( ) {
368- let doneToolbar : UIToolbar = UIToolbar ( frame: CGRect . init ( x: 0 , y: 0 , width: UIScreen . main. bounds. width, height: 50 ) )
369- doneToolbar. barStyle = . default
370-
371- let flexSpace = UIBarButtonItem ( barButtonSystemItem: . flexibleSpace, target: nil , action: nil )
372- let done : UIBarButtonItem = UIBarButtonItem ( title: " Done " , style: . done, target: self , action: #selector( self . doneButtonAction) )
373-
374- let items = [ flexSpace, done]
375- doneToolbar. items = items
376- doneToolbar. sizeToFit ( )
377-
378- self . inputAccessoryView = doneToolbar
379- }
380-
381- @objc func doneButtonAction( ) {
382- self . resignFirstResponder ( )
383- }
384- }
385-
0 commit comments