14
14
15
15
#pragma mark - FlutterTextFieldCell
16
16
/* *
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.
22
19
*/
23
20
@interface FlutterTextFieldCell : NSTextFieldCell
24
21
25
22
/* *
26
23
* Initializes the NSCell for the input NSTextField.
27
24
*/
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 ;
34
26
35
27
@end
36
28
37
29
@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;
41
31
}
42
32
43
33
#pragma mark - Private
44
34
45
- - (instancetype )initWithTextField : (NSTextField *)textField {
35
+ - (instancetype )initWithTextField : (FlutterTextField *)textField andEngine : (FlutterEngine*) engine {
46
36
self = [super initTextCell: textField.stringValue];
47
37
if (self) {
38
+ _engine = engine;
48
39
[self setControlView: textField];
49
40
// Read only text fields are sent to the mac embedding as static
50
41
// texts. This text field must be editable and selectable at this
@@ -55,14 +46,10 @@ - (instancetype)initWithTextField:(NSTextField*)textField {
55
46
return self;
56
47
}
57
48
58
- - (void )setFieldEditor : (FlutterTextInputPlugin*)editor {
59
- _editor = editor;
60
- }
61
-
62
49
#pragma mark - NSCell
63
50
64
51
- (NSTextView *)fieldEditorForView : (NSView *)controlView {
65
- return _editor ;
52
+ return _engine. viewController . textInputPlugin ;
66
53
}
67
54
68
55
@end
@@ -71,38 +58,31 @@ - (NSTextView*)fieldEditorForView:(NSView*)controlView {
71
58
72
59
@implementation FlutterTextField {
73
60
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;
77
62
}
78
63
79
64
#pragma mark - Public
80
65
81
- - (instancetype )initWithPlatformNode : (flutter::FlutterTextPlatformNode*)node {
66
+ - (instancetype )initWithPlatformNode : (flutter::FlutterTextPlatformNode*)node
67
+ andEngine : (FlutterEngine*)engine {
82
68
self = [super initWithFrame: NSZeroRect ];
83
69
if (self) {
84
70
_node = node;
85
- [self setCell: [[FlutterTextFieldCell alloc ] initWithTextField: self ]];
71
+ _engine = engine;
72
+ [self setCell: [[FlutterTextFieldCell alloc ] initWithTextField: self andEngine: engine]];
86
73
}
87
74
return self;
88
75
}
89
76
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
-
98
77
- (void )updateString : (NSString *)string withSelection : (NSRange )selection {
99
- NSAssert (_plugin.client == self,
78
+ FlutterTextInputPlugin* plugin = _engine.viewController .textInputPlugin ;
79
+ NSAssert (plugin.client == self,
100
80
@" Can't update FlutterTextField when it is not the first responder" );
101
81
if (![[self stringValue ] isEqualToString: string]) {
102
82
[self setStringValue: string];
103
83
}
104
- if (!NSEqualRanges (_plugin .selectedRange , selection)) {
105
- [_plugin setSelectedRange: selection];
84
+ if (!NSEqualRanges (plugin .selectedRange , selection)) {
85
+ [plugin setSelectedRange: selection];
106
86
}
107
87
}
108
88
@@ -124,13 +104,17 @@ - (void)setAccessibilityFocused:(BOOL)isFocused {
124
104
#pragma mark - NSResponder
125
105
126
106
- (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 ]) {
128
112
// This text field is already the first responder.
129
113
return YES ;
130
114
}
131
115
BOOL result = [super becomeFirstResponder ];
132
116
if (result) {
133
- _plugin .client = self;
117
+ plugin .client = self;
134
118
// The default implementation of the becomeFirstResponder will change the
135
119
// text editing state. Need to manually set it back.
136
120
NSString * textValue = @(_node->GetStringAttribute (ax::mojom::StringAttribute::kValue ).data ());
@@ -155,16 +139,14 @@ - (BOOL)becomeFirstResponder {
155
139
FlutterEngine* engine) {
156
140
Init (delegate);
157
141
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];
160
143
native_text_field_.bezeled = NO ;
161
144
native_text_field_.drawsBackground = NO ;
162
145
native_text_field_.bordered = NO ;
163
146
native_text_field_.focusRingType = NSFocusRingTypeNone;
164
147
}
165
148
166
149
FlutterTextPlatformNode::~FlutterTextPlatformNode () {
167
- [native_text_field_ setFieldEditor: nil ];
168
150
EnsureDetachedFromView ();
169
151
}
170
152
@@ -176,6 +158,9 @@ - (BOOL)becomeFirstResponder {
176
158
}
177
159
178
160
NSRect FlutterTextPlatformNode::GetFrameRelativeToControllerView () {
161
+ if (!engine_.viewController .viewLoaded ) {
162
+ return NSZeroRect ;
163
+ }
179
164
FlutterPlatformNodeDelegate* delegate = static_cast <FlutterPlatformNodeDelegate*>(GetDelegate ());
180
165
bool offscreen;
181
166
auto bridge_ptr = delegate->GetOwnerBridge ().lock ();
@@ -188,8 +173,9 @@ - (BOOL)becomeFirstResponder {
188
173
// increasing to bottom-right. Flip the y coordinate to convert from Flutter
189
174
// coordinates to macOS coordinates.
190
175
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 ];
193
179
}
194
180
195
181
bool FlutterTextPlatformNode::EnsureAttachedToView () {
0 commit comments