@@ -187,6 +187,8 @@ class EditorTextSelectionOverlay {
187
187
return ;
188
188
}
189
189
handlesVisible = visible;
190
+ // If we are in build state, it will be too late to update visibility.
191
+ // We will need to schedule the build in next frame.
190
192
if (SchedulerBinding .instance! .schedulerPhase ==
191
193
SchedulerPhase .persistentCallbacks) {
192
194
SchedulerBinding .instance! .addPostFrameCallback (markNeedsBuild);
@@ -195,6 +197,7 @@ class EditorTextSelectionOverlay {
195
197
}
196
198
}
197
199
200
+ /// Destroys the handles by removing them from overlay.
198
201
void hideHandles () {
199
202
if (_handles == null ) {
200
203
return ;
@@ -204,13 +207,17 @@ class EditorTextSelectionOverlay {
204
207
_handles = null ;
205
208
}
206
209
210
+ /// Hides the toolbar part of the overlay.
211
+ ///
212
+ /// To hide the whole overlay, see [hide] .
207
213
void hideToolbar () {
208
214
assert (toolbar != null );
209
215
_toolbarController.stop ();
210
216
toolbar! .remove ();
211
217
toolbar = null ;
212
218
}
213
219
220
+ /// Shows the toolbar by inserting it into the [context] 's overlay.
214
221
void showToolbar () {
215
222
assert (toolbar == null );
216
223
toolbar = OverlayEntry (builder: _buildToolbar);
@@ -242,6 +249,15 @@ class EditorTextSelectionOverlay {
242
249
));
243
250
}
244
251
252
+ /// Updates the overlay after the selection has changed.
253
+ ///
254
+ /// If this method is called while the [SchedulerBinding.schedulerPhase] is
255
+ /// [SchedulerPhase.persistentCallbacks] , i.e. during the build, layout, or
256
+ /// paint phases (see [WidgetsBinding.drawFrame] ), then the update is delayed
257
+ /// until the post-frame callbacks phase. Otherwise the update is done
258
+ /// synchronously. This means that it is safe to call during builds, but also
259
+ /// that if you do call this during a build, the UI will not update until the
260
+ /// next frame (i.e. many milliseconds later).
245
261
void update (TextEditingValue newValue) {
246
262
if (value == newValue) {
247
263
return ;
@@ -291,6 +307,7 @@ class EditorTextSelectionOverlay {
291
307
}
292
308
293
309
Widget _buildToolbar (BuildContext context) {
310
+ // Find the horizontal midpoint, just above the selected text.
294
311
final endpoints = renderObject! .getEndpointsForSelection (_selection);
295
312
296
313
final editingRegion = Rect .fromPoints (
@@ -341,6 +358,7 @@ class EditorTextSelectionOverlay {
341
358
toolbar? .markNeedsBuild ();
342
359
}
343
360
361
+ /// Hides the entire overlay including the toolbar and the handles.
344
362
void hide () {
345
363
if (_handles != null ) {
346
364
_handles! [0 ].remove ();
@@ -352,11 +370,13 @@ class EditorTextSelectionOverlay {
352
370
}
353
371
}
354
372
373
+ /// Final cleanup.
355
374
void dispose () {
356
375
hide ();
357
376
_toolbarController.dispose ();
358
377
}
359
378
379
+ /// Builds the handles by inserting them into the [context] 's overlay.
360
380
void showHandles () {
361
381
assert (_handles == null );
362
382
_handles = < OverlayEntry > [
@@ -371,8 +391,17 @@ class EditorTextSelectionOverlay {
371
391
Overlay .of (context, rootOverlay: true , debugRequiredFor: debugRequiredFor)!
372
392
.insertAll (_handles! );
373
393
}
394
+
395
+ /// Causes the overlay to update its rendering.
396
+ ///
397
+ /// This is intended to be called when the [renderObject] may have changed its
398
+ /// text metrics (e.g. because the text was scrolled).
399
+ void updateForScroll () {
400
+ markNeedsBuild ();
401
+ }
374
402
}
375
403
404
+ /// This widget represents a single draggable text selection handle.
376
405
class _TextSelectionHandleOverlay extends StatefulWidget {
377
406
const _TextSelectionHandleOverlay ({
378
407
required this .selection,
0 commit comments