Add a threshold when comparing screen order for selectables. (#130043)
Add a threshold when comparing screen order for selectables. So when the vertical position diff is within the threshold, will compare the horizontal position. This fixes https://github.com/flutter/flutter/issues/111021 and https://github.com/flutter/flutter/issues/127942
This commit is contained in:
@@ -39,6 +39,11 @@ const Set<PointerDeviceKind> _kLongPressSelectionDevices = <PointerDeviceKind>{
|
||||
PointerDeviceKind.invertedStylus,
|
||||
};
|
||||
|
||||
// In practice some selectables like widgetspan shift several pixels. So when
|
||||
// the vertical position diff is within the threshold, compare the horizontal
|
||||
// position to make the compareScreenOrder function more robust.
|
||||
const double _kSelectableVerticalComparingThreshold = 3.0;
|
||||
|
||||
/// A widget that introduces an area for user selections.
|
||||
///
|
||||
/// Flutter widgets are not selectable by default. Wrapping a widget subtree
|
||||
@@ -1703,11 +1708,11 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai
|
||||
/// Returns positive if a is lower, negative if a is higher, 0 if their
|
||||
/// order can't be determine solely by their vertical position.
|
||||
static int _compareVertically(Rect a, Rect b) {
|
||||
if ((a.top - b.top < precisionErrorTolerance && a.bottom - b.bottom > - precisionErrorTolerance) ||
|
||||
(b.top - a.top < precisionErrorTolerance && b.bottom - a.bottom > - precisionErrorTolerance)) {
|
||||
if ((a.top - b.top < _kSelectableVerticalComparingThreshold && a.bottom - b.bottom > - _kSelectableVerticalComparingThreshold) ||
|
||||
(b.top - a.top < _kSelectableVerticalComparingThreshold && b.bottom - a.bottom > - _kSelectableVerticalComparingThreshold)) {
|
||||
return 0;
|
||||
}
|
||||
if ((a.top - b.top).abs() > precisionErrorTolerance) {
|
||||
if ((a.top - b.top).abs() > _kSelectableVerticalComparingThreshold) {
|
||||
return a.top > b.top ? 1 : -1;
|
||||
}
|
||||
return a.bottom > b.bottom ? 1 : -1;
|
||||
|
||||
@@ -2469,6 +2469,51 @@ void main() {
|
||||
skip: !kIsWeb, // [intended]
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Multiple selectables on a single line should be in screen order', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/127942.
|
||||
final UniqueKey outerText = UniqueKey();
|
||||
const TextStyle textStyle = TextStyle(fontSize: 10);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: SelectableRegion(
|
||||
focusNode: FocusNode(),
|
||||
selectionControls: materialTextSelectionControls,
|
||||
child: Scaffold(
|
||||
body: Center(
|
||||
child: Text.rich(
|
||||
const TextSpan(
|
||||
children: <InlineSpan>[
|
||||
TextSpan(text: 'Hello my name is ', style: textStyle),
|
||||
WidgetSpan(
|
||||
child: Text('Dash', style: textStyle),
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
),
|
||||
TextSpan(text: '.', style: textStyle),
|
||||
],
|
||||
),
|
||||
key: outerText,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
final RenderParagraph paragraph1 = tester.renderObject<RenderParagraph>(find.descendant(of: find.byKey(outerText), matching: find.byType(RichText)).first);
|
||||
final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 0), kind: PointerDeviceKind.mouse);
|
||||
addTearDown(gesture.removePointer);
|
||||
await tester.pump();
|
||||
await gesture.up();
|
||||
|
||||
// Select all.
|
||||
await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.keyA, control: true));
|
||||
|
||||
// keyboard copy.
|
||||
await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.keyC, control: true));
|
||||
|
||||
final Map<String, dynamic> clipboardData = mockClipboard.clipboardData as Map<String, dynamic>;
|
||||
expect(clipboardData['text'], 'Hello my name is Dash.');
|
||||
});
|
||||
}
|
||||
|
||||
class SelectionSpy extends LeafRenderObjectWidget {
|
||||
|
||||
Reference in New Issue
Block a user