1414
1515#pragma mark - FlutterTextFieldCell
1616/* *
17- * A convenient class that can be used to set a custom field editor for a
18- * NSTextField.
19- *
20- * The FlutterTextField uses this class set the FlutterTextInputPlugin as
21- * its field editor.
17+ * The NSCell for FlutterTextField that it sets the field editor of FlutterTextField
18+ * to the text input plugin from the FlutterTextFieldDelegate.
2219 */
2320@interface FlutterTextFieldCell : NSTextFieldCell
2421
2522/* *
2623 * Initializes the NSCell for the input NSTextField.
2724 */
28- - (instancetype )initWithTextField : (NSTextField *)textField ;
29-
30- /* *
31- * Assign the field editor to be used by the NSTextField.
32- */
33- - (void )setFieldEditor : (FlutterTextInputPlugin*)editor ;
25+ - (instancetype )initWithTextField : (FlutterTextField*)textField andEngine : (FlutterEngine*)engine ;
3426
3527@end
3628
3729@implementation FlutterTextFieldCell {
38- // NSTextView does not support _weak reference, so this class stores
39- // __unsafe_unretained.
40- __unsafe_unretained NSTextView * _editor;
30+ __weak FlutterEngine* _engine;
4131}
4232
4333#pragma mark - Private
4434
45- - (instancetype )initWithTextField : (NSTextField *)textField {
35+ - (instancetype )initWithTextField : (FlutterTextField *)textField andEngine : (FlutterEngine*) engine {
4636 self = [super initTextCell: textField.stringValue];
4737 if (self) {
38+ _engine = engine;
4839 [self setControlView: textField];
4940 // Read only text fields are sent to the mac embedding as static
5041 // texts. This text field must be editable and selectable at this
@@ -55,14 +46,10 @@ - (instancetype)initWithTextField:(NSTextField*)textField {
5546 return self;
5647}
5748
58- - (void )setFieldEditor : (FlutterTextInputPlugin*)editor {
59- _editor = editor;
60- }
61-
6249#pragma mark - NSCell
6350
6451- (NSTextView *)fieldEditorForView : (NSView *)controlView {
65- return _editor ;
52+ return _engine. viewController . textInputPlugin ;
6653}
6754
6855@end
@@ -71,38 +58,31 @@ - (NSTextView*)fieldEditorForView:(NSView*)controlView {
7158
7259@implementation FlutterTextField {
7360 flutter::FlutterTextPlatformNode* _node;
74- // NSTextView does not support _weak reference, so this class holds
75- // __unsafe_unretained.
76- __unsafe_unretained FlutterTextInputPlugin* _plugin;
61+ __weak FlutterEngine* _engine;
7762}
7863
7964#pragma mark - Public
8065
81- - (instancetype )initWithPlatformNode : (flutter::FlutterTextPlatformNode*)node {
66+ - (instancetype )initWithPlatformNode : (flutter::FlutterTextPlatformNode*)node
67+ andEngine : (FlutterEngine*)engine {
8268 self = [super initWithFrame: NSZeroRect ];
8369 if (self) {
8470 _node = node;
85- [self setCell: [[FlutterTextFieldCell alloc ] initWithTextField: self ]];
71+ _engine = engine;
72+ [self setCell: [[FlutterTextFieldCell alloc ] initWithTextField: self andEngine: engine]];
8673 }
8774 return self;
8875}
8976
90- - (void )setFieldEditor : (FlutterTextInputPlugin*)plugin {
91- _plugin = plugin;
92- NSAssert ([self .cell isKindOfClass: [FlutterTextFieldCell class ]],
93- @" The cell of a FlutterTextField must be a FlutterTextFieldCell" );
94- FlutterTextFieldCell* cell = (FlutterTextFieldCell*)self.cell ;
95- [cell setFieldEditor: plugin];
96- }
97-
9877- (void )updateString : (NSString *)string withSelection : (NSRange )selection {
99- NSAssert (_plugin.client == self,
78+ FlutterTextInputPlugin* plugin = _engine.viewController .textInputPlugin ;
79+ NSAssert (plugin.client == self,
10080 @" Can't update FlutterTextField when it is not the first responder" );
10181 if (![[self stringValue ] isEqualToString: string]) {
10282 [self setStringValue: string];
10383 }
104- if (!NSEqualRanges (_plugin .selectedRange , selection)) {
105- [_plugin setSelectedRange: selection];
84+ if (!NSEqualRanges (plugin .selectedRange , selection)) {
85+ [plugin setSelectedRange: selection];
10686 }
10787}
10888
@@ -124,13 +104,17 @@ - (void)setAccessibilityFocused:(BOOL)isFocused {
124104#pragma mark - NSResponder
125105
126106- (BOOL )becomeFirstResponder {
127- if (_plugin.client == self && [_plugin isFirstResponder ]) {
107+ FlutterTextInputPlugin* plugin = _engine.viewController .textInputPlugin ;
108+ if (!plugin) {
109+ return NO ;
110+ }
111+ if (plugin.client == self && [plugin isFirstResponder ]) {
128112 // This text field is already the first responder.
129113 return YES ;
130114 }
131115 BOOL result = [super becomeFirstResponder ];
132116 if (result) {
133- _plugin .client = self;
117+ plugin .client = self;
134118 // The default implementation of the becomeFirstResponder will change the
135119 // text editing state. Need to manually set it back.
136120 NSString * textValue = @(_node->GetStringAttribute (ax::mojom::StringAttribute::kValue ).data ());
@@ -155,16 +139,14 @@ - (BOOL)becomeFirstResponder {
155139 FlutterEngine* engine) {
156140 Init (delegate);
157141 engine_ = engine;
158- native_text_field_ = [[FlutterTextField alloc ] initWithPlatformNode: this ];
159- [native_text_field_ setFieldEditor: engine.viewController.textInputPlugin];
142+ native_text_field_ = [[FlutterTextField alloc ] initWithPlatformNode: this andEngine: engine];
160143 native_text_field_.bezeled = NO ;
161144 native_text_field_.drawsBackground = NO ;
162145 native_text_field_.bordered = NO ;
163146 native_text_field_.focusRingType = NSFocusRingTypeNone;
164147}
165148
166149FlutterTextPlatformNode::~FlutterTextPlatformNode () {
167- [native_text_field_ setFieldEditor: nil ];
168150 EnsureDetachedFromView ();
169151}
170152
@@ -176,6 +158,9 @@ - (BOOL)becomeFirstResponder {
176158}
177159
178160NSRect FlutterTextPlatformNode::GetFrameRelativeToControllerView () {
161+ if (!engine_.viewController .viewLoaded ) {
162+ return NSZeroRect ;
163+ }
179164 FlutterPlatformNodeDelegate* delegate = static_cast <FlutterPlatformNodeDelegate*>(GetDelegate ());
180165 bool offscreen;
181166 auto bridge_ptr = delegate->GetOwnerBridge ().lock ();
@@ -188,8 +173,9 @@ - (BOOL)becomeFirstResponder {
188173 // increasing to bottom-right. Flip the y coordinate to convert from Flutter
189174 // coordinates to macOS coordinates.
190175 ns_local_bounds.origin .y = -ns_local_bounds.origin .y - ns_local_bounds.size .height ;
191- return [engine_.viewController.flutterView convertRectFromBacking: ns_local_bounds];
192- ;
176+ NSRect ns_view_bounds =
177+ [engine_.viewController.flutterView convertRectFromBacking: ns_local_bounds];
178+ return [engine_.viewController.flutterView convertRect: ns_view_bounds toView: nil ];
193179}
194180
195181bool FlutterTextPlatformNode::EnsureAttachedToView () {
0 commit comments