Unverified Commit b80bbd55 authored by hangyu's avatar hangyu Committed by GitHub

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
parent 3b8f6c40
......@@ -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 {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment