@@ -37,7 +37,6 @@ import 'text_selection.dart';
37
37
import 'text_selection_toolbar_anchors.dart' ;
38
38
39
39
// Examples can assume:
40
- // FocusNode _focusNode = FocusNode();
41
40
// late GlobalKey key;
42
41
43
42
const Set <PointerDeviceKind > _kLongPressSelectionDevices = < PointerDeviceKind > {
@@ -105,7 +104,6 @@ const double _kSelectableVerticalComparingThreshold = 3.0;
105
104
/// MaterialApp(
106
105
/// home: SelectableRegion(
107
106
/// selectionControls: materialTextSelectionControls,
108
- /// focusNode: _focusNode, // initialized to FocusNode()
109
107
/// child: Scaffold(
110
108
/// appBar: AppBar(title: const Text('Flutter Code Sample')),
111
109
/// body: ListView(
@@ -218,7 +216,7 @@ class SelectableRegion extends StatefulWidget {
218
216
const SelectableRegion ({
219
217
super .key,
220
218
this .contextMenuBuilder,
221
- required this .focusNode,
219
+ this .focusNode,
222
220
required this .selectionControls,
223
221
required this .child,
224
222
this .magnifierConfiguration = TextMagnifierConfiguration .disabled,
@@ -235,7 +233,7 @@ class SelectableRegion extends StatefulWidget {
235
233
final TextMagnifierConfiguration magnifierConfiguration;
236
234
237
235
/// {@macro flutter.widgets.Focus.focusNode}
238
- final FocusNode focusNode;
236
+ final FocusNode ? focusNode;
239
237
240
238
/// The child widget this selection area applies to.
241
239
///
@@ -373,10 +371,14 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
373
371
/// The list of native text processing actions provided by the engine.
374
372
final List <ProcessTextAction > _processTextActions = < ProcessTextAction > [];
375
373
374
+ // The focus node to use if the widget didn't supply one.
375
+ FocusNode ? _localFocusNode;
376
+ FocusNode get _focusNode => widget.focusNode ?? (_localFocusNode ?? = FocusNode (debugLabel: 'SelectableRegion' ));
377
+
376
378
@override
377
379
void initState () {
378
380
super .initState ();
379
- widget.focusNode .addListener (_handleFocusChanged);
381
+ _focusNode .addListener (_handleFocusChanged);
380
382
_initMouseGestureRecognizer ();
381
383
_initTouchGestureRecognizer ();
382
384
// Right clicks.
@@ -426,9 +428,15 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
426
428
void didUpdateWidget (SelectableRegion oldWidget) {
427
429
super .didUpdateWidget (oldWidget);
428
430
if (widget.focusNode != oldWidget.focusNode) {
429
- oldWidget.focusNode.removeListener (_handleFocusChanged);
430
- widget.focusNode.addListener (_handleFocusChanged);
431
- if (widget.focusNode.hasFocus != oldWidget.focusNode.hasFocus) {
431
+ if (oldWidget.focusNode == null && widget.focusNode != null ) {
432
+ _localFocusNode? .removeListener (_handleFocusChanged);
433
+ _localFocusNode? .dispose ();
434
+ _localFocusNode = null ;
435
+ } else if (widget.focusNode == null && oldWidget.focusNode != null ) {
436
+ oldWidget.focusNode! .removeListener (_handleFocusChanged);
437
+ }
438
+ _focusNode.addListener (_handleFocusChanged);
439
+ if (_focusNode.hasFocus != oldWidget.focusNode? .hasFocus) {
432
440
_handleFocusChanged ();
433
441
}
434
442
}
@@ -439,7 +447,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
439
447
}
440
448
441
449
void _handleFocusChanged () {
442
- if (! widget.focusNode .hasFocus) {
450
+ if (! _focusNode .hasFocus) {
443
451
if (kIsWeb) {
444
452
PlatformSelectableRegionContextMenu .detach (_selectionDelegate);
445
453
}
@@ -628,7 +636,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
628
636
_lastPointerDeviceKind = details.kind;
629
637
switch (_getEffectiveConsecutiveTapCount (details.consecutiveTapCount)) {
630
638
case 1 :
631
- widget.focusNode .requestFocus ();
639
+ _focusNode .requestFocus ();
632
640
switch (defaultTargetPlatform) {
633
641
case TargetPlatform .android:
634
642
case TargetPlatform .fuchsia:
@@ -843,7 +851,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
843
851
844
852
void _handleTouchLongPressStart (LongPressStartDetails details) {
845
853
HapticFeedback .selectionClick ();
846
- widget.focusNode .requestFocus ();
854
+ _focusNode .requestFocus ();
847
855
_selectWordAt (offset: details.globalPosition);
848
856
// Platforms besides Android will show the text selection handles when
849
857
// the long press is initiated. Android shows the text selection handles when
@@ -883,7 +891,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
883
891
final Offset ? previousSecondaryTapDownPosition = _lastSecondaryTapDownPosition;
884
892
final bool toolbarIsVisible = _selectionOverlay? .toolbarIsVisible ?? false ;
885
893
_lastSecondaryTapDownPosition = details.globalPosition;
886
- widget.focusNode .requestFocus ();
894
+ _focusNode .requestFocus ();
887
895
switch (defaultTargetPlatform) {
888
896
case TargetPlatform .android:
889
897
case TargetPlatform .fuchsia:
@@ -1706,6 +1714,9 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
1706
1714
_selectionOverlay? .hideMagnifier ();
1707
1715
_selectionOverlay? .dispose ();
1708
1716
_selectionOverlay = null ;
1717
+ widget.focusNode? .removeListener (_handleFocusChanged);
1718
+ _localFocusNode? .removeListener (_handleFocusChanged);
1719
+ _localFocusNode? .dispose ();
1709
1720
super .dispose ();
1710
1721
}
1711
1722
@@ -1730,9 +1741,9 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
1730
1741
excludeFromSemantics: true ,
1731
1742
child: Actions (
1732
1743
actions: _actions,
1733
- child: Focus (
1744
+ child: Focus . withExternalFocusNode (
1734
1745
includeSemantics: false ,
1735
- focusNode: widget.focusNode ,
1746
+ focusNode: _focusNode ,
1736
1747
child: result,
1737
1748
),
1738
1749
),
0 commit comments