@@ -515,6 +515,11 @@ class TextSelectionOverlay {
515
515
}
516
516
_value = newValue;
517
517
_updateSelectionOverlay ();
518
+ // _updateSelectionOverlay may not rebuild the selection overlay if the
519
+ // text metrics and selection doesn't change even if the text has changed.
520
+ // This rebuild is needed for the toolbar to update based on the latest text
521
+ // value.
522
+ _selectionOverlay.markNeedsBuild ();
518
523
}
519
524
520
525
void _updateSelectionOverlay () {
@@ -541,7 +546,13 @@ class TextSelectionOverlay {
541
546
///
542
547
/// This is intended to be called when the [renderObject] may have changed its
543
548
/// text metrics (e.g. because the text was scrolled).
544
- void updateForScroll () => _updateSelectionOverlay ();
549
+ void updateForScroll () {
550
+ _updateSelectionOverlay ();
551
+ // This method may be called due to windows metrics changes. In that case,
552
+ // non of the properties in _selectionOverlay will change, but a rebuild is
553
+ // still needed.
554
+ _selectionOverlay.markNeedsBuild ();
555
+ }
545
556
546
557
/// Whether the handles are currently visible.
547
558
bool get handlesAreVisible => _selectionOverlay._handles != null && handlesVisible;
@@ -1030,7 +1041,7 @@ class SelectionOverlay {
1030
1041
return ;
1031
1042
}
1032
1043
_startHandleType = value;
1033
- _markNeedsBuild ();
1044
+ markNeedsBuild ();
1034
1045
}
1035
1046
1036
1047
/// The line height at the selection start.
@@ -1045,9 +1056,11 @@ class SelectionOverlay {
1045
1056
return ;
1046
1057
}
1047
1058
_lineHeightAtStart = value;
1048
- _markNeedsBuild ();
1059
+ markNeedsBuild ();
1049
1060
}
1050
1061
1062
+ bool _isDraggingStartHandle = false ;
1063
+
1051
1064
/// Whether the start handle is visible.
1052
1065
///
1053
1066
/// If the value changes, the start handle uses [FadeTransition] to transition
@@ -1059,13 +1072,24 @@ class SelectionOverlay {
1059
1072
/// Called when the users start dragging the start selection handles.
1060
1073
final ValueChanged <DragStartDetails >? onStartHandleDragStart;
1061
1074
1075
+ void _handleStartHandleDragStart (DragStartDetails details) {
1076
+ assert (! _isDraggingStartHandle);
1077
+ _isDraggingStartHandle = details.kind == PointerDeviceKind .touch;
1078
+ onStartHandleDragStart? .call (details);
1079
+ }
1080
+
1062
1081
/// Called when the users drag the start selection handles to new locations.
1063
1082
final ValueChanged <DragUpdateDetails >? onStartHandleDragUpdate;
1064
1083
1065
1084
/// Called when the users lift their fingers after dragging the start selection
1066
1085
/// handles.
1067
1086
final ValueChanged <DragEndDetails >? onStartHandleDragEnd;
1068
1087
1088
+ void _handleStartHandleDragEnd (DragEndDetails details) {
1089
+ _isDraggingStartHandle = false ;
1090
+ onStartHandleDragEnd? .call (details);
1091
+ }
1092
+
1069
1093
/// The type of end selection handle.
1070
1094
///
1071
1095
/// Changing the value while the handles are visible causes them to rebuild.
@@ -1076,7 +1100,7 @@ class SelectionOverlay {
1076
1100
return ;
1077
1101
}
1078
1102
_endHandleType = value;
1079
- _markNeedsBuild ();
1103
+ markNeedsBuild ();
1080
1104
}
1081
1105
1082
1106
/// The line height at the selection end.
@@ -1091,9 +1115,11 @@ class SelectionOverlay {
1091
1115
return ;
1092
1116
}
1093
1117
_lineHeightAtEnd = value;
1094
- _markNeedsBuild ();
1118
+ markNeedsBuild ();
1095
1119
}
1096
1120
1121
+ bool _isDraggingEndHandle = false ;
1122
+
1097
1123
/// Whether the end handle is visible.
1098
1124
///
1099
1125
/// If the value changes, the end handle uses [FadeTransition] to transition
@@ -1105,13 +1131,24 @@ class SelectionOverlay {
1105
1131
/// Called when the users start dragging the end selection handles.
1106
1132
final ValueChanged <DragStartDetails >? onEndHandleDragStart;
1107
1133
1134
+ void _handleEndHandleDragStart (DragStartDetails details) {
1135
+ assert (! _isDraggingEndHandle);
1136
+ _isDraggingEndHandle = details.kind == PointerDeviceKind .touch;
1137
+ onEndHandleDragStart? .call (details);
1138
+ }
1139
+
1108
1140
/// Called when the users drag the end selection handles to new locations.
1109
1141
final ValueChanged <DragUpdateDetails >? onEndHandleDragUpdate;
1110
1142
1111
1143
/// Called when the users lift their fingers after dragging the end selection
1112
1144
/// handles.
1113
1145
final ValueChanged <DragEndDetails >? onEndHandleDragEnd;
1114
1146
1147
+ void _handleEndHandleDragEnd (DragEndDetails details) {
1148
+ _isDraggingEndHandle = false ;
1149
+ onEndHandleDragEnd? .call (details);
1150
+ }
1151
+
1115
1152
/// Whether the toolbar is visible.
1116
1153
///
1117
1154
/// If the value changes, the toolbar uses [FadeTransition] to transition
@@ -1125,7 +1162,21 @@ class SelectionOverlay {
1125
1162
List <TextSelectionPoint > _selectionEndpoints;
1126
1163
set selectionEndpoints (List <TextSelectionPoint > value) {
1127
1164
if (! listEquals (_selectionEndpoints, value)) {
1128
- _markNeedsBuild ();
1165
+ markNeedsBuild ();
1166
+ if ((_isDraggingEndHandle || _isDraggingStartHandle) &&
1167
+ _startHandleType != TextSelectionHandleType .collapsed) {
1168
+ switch (defaultTargetPlatform) {
1169
+ case TargetPlatform .android:
1170
+ HapticFeedback .selectionClick ();
1171
+ break ;
1172
+ case TargetPlatform .fuchsia:
1173
+ case TargetPlatform .iOS:
1174
+ case TargetPlatform .linux:
1175
+ case TargetPlatform .macOS:
1176
+ case TargetPlatform .windows:
1177
+ break ;
1178
+ }
1179
+ }
1129
1180
}
1130
1181
_selectionEndpoints = value;
1131
1182
}
@@ -1220,7 +1271,7 @@ class SelectionOverlay {
1220
1271
return ;
1221
1272
}
1222
1273
_toolbarLocation = value;
1223
- _markNeedsBuild ();
1274
+ markNeedsBuild ();
1224
1275
}
1225
1276
1226
1277
/// Controls the fade-in and fade-out animations for the toolbar and handles.
@@ -1250,7 +1301,6 @@ class SelectionOverlay {
1250
1301
OverlayEntry (builder: _buildStartHandle),
1251
1302
OverlayEntry (builder: _buildEndHandle),
1252
1303
];
1253
-
1254
1304
Overlay .of (context, rootOverlay: true , debugRequiredFor: debugRequiredFor).insertAll (_handles! );
1255
1305
}
1256
1306
@@ -1299,7 +1349,9 @@ class SelectionOverlay {
1299
1349
}
1300
1350
1301
1351
bool _buildScheduled = false ;
1302
- void _markNeedsBuild () {
1352
+
1353
+ /// Rebuilds the selection toolbar or handles if they are present.
1354
+ void markNeedsBuild () {
1303
1355
if (_handles == null && _toolbar == null ) {
1304
1356
return ;
1305
1357
}
@@ -1379,9 +1431,9 @@ class SelectionOverlay {
1379
1431
type: _startHandleType,
1380
1432
handleLayerLink: startHandleLayerLink,
1381
1433
onSelectionHandleTapped: onSelectionHandleTapped,
1382
- onSelectionHandleDragStart: onStartHandleDragStart ,
1434
+ onSelectionHandleDragStart: _handleStartHandleDragStart ,
1383
1435
onSelectionHandleDragUpdate: onStartHandleDragUpdate,
1384
- onSelectionHandleDragEnd: onStartHandleDragEnd ,
1436
+ onSelectionHandleDragEnd: _handleStartHandleDragEnd ,
1385
1437
selectionControls: selectionControls,
1386
1438
visibility: startHandlesVisible,
1387
1439
preferredLineHeight: _lineHeightAtStart,
@@ -1406,9 +1458,9 @@ class SelectionOverlay {
1406
1458
type: _endHandleType,
1407
1459
handleLayerLink: endHandleLayerLink,
1408
1460
onSelectionHandleTapped: onSelectionHandleTapped,
1409
- onSelectionHandleDragStart: onEndHandleDragStart ,
1461
+ onSelectionHandleDragStart: _handleEndHandleDragStart ,
1410
1462
onSelectionHandleDragUpdate: onEndHandleDragUpdate,
1411
- onSelectionHandleDragEnd: onEndHandleDragEnd ,
1463
+ onSelectionHandleDragEnd: _handleEndHandleDragEnd ,
1412
1464
selectionControls: selectionControls,
1413
1465
visibility: endHandlesVisible,
1414
1466
preferredLineHeight: _lineHeightAtEnd,
0 commit comments