Adjust selection drag start position for viewport offset changes (#80047)
This commit is contained in:
parent
884fdf2e33
commit
24f0d28562
@ -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.
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user