Adjust selection drag start position for viewport offset changes (#80047)

This commit is contained in:
Tomasz Gucio 2021-04-22 03:34:03 +02:00 committed by GitHub
parent 884fdf2e33
commit 24f0d28562
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 3 deletions

View File

@ -952,7 +952,7 @@ class TextSelectionGestureDetectorBuilder {
@protected
final TextSelectionGestureDetectorBuilderDelegate delegate;
/// Returns true iff lastSecondaryTapDownPosition was on selection.
/// Returns true if lastSecondaryTapDownPosition was on selection.
bool get _lastSecondaryTapWasOnSelection {
assert(renderEditable.lastSecondaryTapDownPosition != null);
if (renderEditable.selection == null) {
@ -985,6 +985,9 @@ class TextSelectionGestureDetectorBuilder {
@protected
RenderEditable get renderEditable => editableText.renderEditable;
/// The viewport offset pixels of the [RenderEditable] at the last drag start.
double _dragStartViewportOffset = 0.0;
/// Handler for [TextSelectionGestureDetector.onTapDown].
///
/// By default, it forwards the tap to [RenderEditable.handleTapDown] and sets
@ -1197,6 +1200,8 @@ class TextSelectionGestureDetectorBuilder {
from: details.globalPosition,
cause: SelectionChangedCause.drag,
);
_dragStartViewportOffset = renderEditable.offset.pixels;
}
/// Handler for [TextSelectionGestureDetector.onDragSelectionUpdate].
@ -1212,8 +1217,14 @@ class TextSelectionGestureDetectorBuilder {
void onDragSelectionUpdate(DragStartDetails startDetails, DragUpdateDetails updateDetails) {
if (!delegate.selectionEnabled)
return;
// Adjust the drag start offset for possible viewport offset changes.
final Offset startOffset = renderEditable.maxLines == 1
? Offset(renderEditable.offset.pixels - _dragStartViewportOffset, 0.0)
: Offset(0.0, renderEditable.offset.pixels - _dragStartViewportOffset);
renderEditable.selectPositionAt(
from: startDetails.globalPosition,
from: startDetails.globalPosition - startOffset,
to: updateDetails.globalPosition,
cause: SelectionChangedCause.drag,
);
@ -1618,7 +1629,7 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget
}) : super(value);
bool _disposed = false;
/// True iff this instance has been disposed.
/// True if this instance has been disposed.
bool get disposed => _disposed;
/// Check the [Clipboard] and update [value] if needed.

View File

@ -624,6 +624,44 @@ void main() {
expect(editableText.selectionOverlay!.toolbarIsVisible, isFalse);
});
testWidgets('test TextSelectionGestureDetectorBuilder drag with RenderEditable viewport offset change', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable));
// Reconfigure the RenderEditable for multi-line.
renderEditable.maxLines = null;
renderEditable.offset = ViewportOffset.fixed(20.0);
renderEditable.layout(const BoxConstraints.tightFor(width: 400, height: 300.0));
await tester.pumpAndSettle();
final TestGesture gesture = await tester.startGesture(
const Offset(200.0, 200.0),
kind: PointerDeviceKind.mouse,
);
addTearDown(gesture.removePointer);
await tester.pumpAndSettle();
expect(renderEditable.selectPositionAtCalled, isFalse);
await gesture.moveTo(const Offset(300.0, 200.0));
await tester.pumpAndSettle();
expect(renderEditable.selectPositionAtCalled, isTrue);
expect(renderEditable.selectPositionAtFrom, const Offset(200.0, 200.0));
expect(renderEditable.selectPositionAtTo, const Offset(300.0, 200.0));
// Move the viewport offset (scroll).
renderEditable.offset = ViewportOffset.fixed(150.0);
renderEditable.layout(const BoxConstraints.tightFor(width: 400, height: 300.0));
await tester.pumpAndSettle();
await gesture.moveTo(const Offset(300.0, 400.0));
await tester.pumpAndSettle();
await gesture.up();
await tester.pumpAndSettle();
expect(renderEditable.selectPositionAtCalled, isTrue);
expect(renderEditable.selectPositionAtFrom, const Offset(200.0, 70.0));
expect(renderEditable.selectPositionAtTo, const Offset(300.0, 400.0));
});
testWidgets('test TextSelectionGestureDetectorBuilder selection disabled', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester, selectionEnabled: false);
final TestGesture gesture = await tester.startGesture(
@ -863,9 +901,13 @@ class FakeRenderEditable extends RenderEditable {
}
bool selectPositionAtCalled = false;
Offset? selectPositionAtFrom;
Offset? selectPositionAtTo;
@override
void selectPositionAt({ required Offset from, Offset? to, required SelectionChangedCause cause }) {
selectPositionAtCalled = true;
selectPositionAtFrom = from;
selectPositionAtTo = to;
}
bool selectWordCalled = false;