Handle dragging improvements (#114042)
Improves the feel of dragging text selection vertically between lines on mobile.
This commit is contained in:
parent
d0afbd72a7
commit
93b0042559
@ -637,7 +637,13 @@ class TextSelectionOverlay {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
late Offset _dragEndPosition;
|
// The contact position of the gesture at the current end handle location.
|
||||||
|
// Updated when the handle moves.
|
||||||
|
late double _endHandleDragPosition;
|
||||||
|
|
||||||
|
// The distance from _endHandleDragPosition to the center of the line that it
|
||||||
|
// corresponds to.
|
||||||
|
late double _endHandleDragPositionToCenterOfLine;
|
||||||
|
|
||||||
void _handleSelectionEndHandleDragStart(DragStartDetails details) {
|
void _handleSelectionEndHandleDragStart(DragStartDetails details) {
|
||||||
if (!renderObject.attached) {
|
if (!renderObject.attached) {
|
||||||
@ -646,10 +652,17 @@ class TextSelectionOverlay {
|
|||||||
|
|
||||||
// This adjusts for the fact that the selection handles may not
|
// This adjusts for the fact that the selection handles may not
|
||||||
// perfectly cover the TextPosition that they correspond to.
|
// perfectly cover the TextPosition that they correspond to.
|
||||||
final Offset offsetFromHandleToTextPosition = _getOffsetToTextPositionPoint(_selectionOverlay.endHandleType);
|
_endHandleDragPosition = details.globalPosition.dy;
|
||||||
_dragEndPosition = details.globalPosition + offsetFromHandleToTextPosition;
|
final Offset endPoint =
|
||||||
|
renderObject.localToGlobal(_selectionOverlay.selectionEndpoints.last.point);
|
||||||
final TextPosition position = renderObject.getPositionForPoint(_dragEndPosition);
|
final double centerOfLine = endPoint.dy - renderObject.preferredLineHeight / 2;
|
||||||
|
_endHandleDragPositionToCenterOfLine = centerOfLine - _endHandleDragPosition;
|
||||||
|
final TextPosition position = renderObject.getPositionForPoint(
|
||||||
|
Offset(
|
||||||
|
details.globalPosition.dx,
|
||||||
|
centerOfLine,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
_selectionOverlay.showMagnifier(
|
_selectionOverlay.showMagnifier(
|
||||||
_buildMagnifier(
|
_buildMagnifier(
|
||||||
@ -660,14 +673,33 @@ class TextSelectionOverlay {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a handle position and drag position, returns the position of handle
|
||||||
|
/// after the drag.
|
||||||
|
///
|
||||||
|
/// The handle jumps instantly between lines when the drag reaches a full
|
||||||
|
/// line's height away from the original handle position. In other words, the
|
||||||
|
/// line jump happens when the contact point would be located at the same
|
||||||
|
/// place on the handle at the new line as when the gesture started.
|
||||||
|
double _getHandleDy(double dragDy, double handleDy) {
|
||||||
|
final double distanceDragged = dragDy - handleDy;
|
||||||
|
final int dragDirection = distanceDragged < 0.0 ? -1 : 1;
|
||||||
|
final int linesDragged =
|
||||||
|
dragDirection * (distanceDragged.abs() / renderObject.preferredLineHeight).floor();
|
||||||
|
return handleDy + linesDragged * renderObject.preferredLineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
void _handleSelectionEndHandleDragUpdate(DragUpdateDetails details) {
|
void _handleSelectionEndHandleDragUpdate(DragUpdateDetails details) {
|
||||||
if (!renderObject.attached) {
|
if (!renderObject.attached) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_dragEndPosition += details.delta;
|
|
||||||
|
|
||||||
final TextPosition position = renderObject.getPositionForPoint(_dragEndPosition);
|
_endHandleDragPosition = _getHandleDy(details.globalPosition.dy, _endHandleDragPosition);
|
||||||
final TextSelection currentSelection = TextSelection.fromPosition(position);
|
final Offset adjustedOffset = Offset(
|
||||||
|
details.globalPosition.dx,
|
||||||
|
_endHandleDragPosition + _endHandleDragPositionToCenterOfLine,
|
||||||
|
);
|
||||||
|
|
||||||
|
final TextPosition position = renderObject.getPositionForPoint(adjustedOffset);
|
||||||
|
|
||||||
if (_selection.isCollapsed) {
|
if (_selection.isCollapsed) {
|
||||||
_selectionOverlay.updateMagnifier(_buildMagnifier(
|
_selectionOverlay.updateMagnifier(_buildMagnifier(
|
||||||
@ -676,6 +708,7 @@ class TextSelectionOverlay {
|
|||||||
renderEditable: renderObject,
|
renderEditable: renderObject,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
final TextSelection currentSelection = TextSelection.fromPosition(position);
|
||||||
_handleSelectionHandleChanged(currentSelection, isEnd: true);
|
_handleSelectionHandleChanged(currentSelection, isEnd: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -716,7 +749,13 @@ class TextSelectionOverlay {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
late Offset _dragStartPosition;
|
// The contact position of the gesture at the current start handle location.
|
||||||
|
// Updated when the handle moves.
|
||||||
|
late double _startHandleDragPosition;
|
||||||
|
|
||||||
|
// The distance from _startHandleDragPosition to the center of the line that
|
||||||
|
// it corresponds to.
|
||||||
|
late double _startHandleDragPositionToCenterOfLine;
|
||||||
|
|
||||||
void _handleSelectionStartHandleDragStart(DragStartDetails details) {
|
void _handleSelectionStartHandleDragStart(DragStartDetails details) {
|
||||||
if (!renderObject.attached) {
|
if (!renderObject.attached) {
|
||||||
@ -725,10 +764,17 @@ class TextSelectionOverlay {
|
|||||||
|
|
||||||
// This adjusts for the fact that the selection handles may not
|
// This adjusts for the fact that the selection handles may not
|
||||||
// perfectly cover the TextPosition that they correspond to.
|
// perfectly cover the TextPosition that they correspond to.
|
||||||
final Offset offsetFromHandleToTextPosition = _getOffsetToTextPositionPoint(_selectionOverlay.startHandleType);
|
_startHandleDragPosition = details.globalPosition.dy;
|
||||||
_dragStartPosition = details.globalPosition + offsetFromHandleToTextPosition;
|
final Offset startPoint =
|
||||||
|
renderObject.localToGlobal(_selectionOverlay.selectionEndpoints.first.point);
|
||||||
final TextPosition position = renderObject.getPositionForPoint(_dragStartPosition);
|
final double centerOfLine = startPoint.dy - renderObject.preferredLineHeight / 2;
|
||||||
|
_startHandleDragPositionToCenterOfLine = centerOfLine - _startHandleDragPosition;
|
||||||
|
final TextPosition position = renderObject.getPositionForPoint(
|
||||||
|
Offset(
|
||||||
|
details.globalPosition.dx,
|
||||||
|
centerOfLine,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
_selectionOverlay.showMagnifier(
|
_selectionOverlay.showMagnifier(
|
||||||
_buildMagnifier(
|
_buildMagnifier(
|
||||||
@ -743,8 +789,13 @@ class TextSelectionOverlay {
|
|||||||
if (!renderObject.attached) {
|
if (!renderObject.attached) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_dragStartPosition += details.delta;
|
|
||||||
final TextPosition position = renderObject.getPositionForPoint(_dragStartPosition);
|
_startHandleDragPosition = _getHandleDy(details.globalPosition.dy, _startHandleDragPosition);
|
||||||
|
final Offset adjustedOffset = Offset(
|
||||||
|
details.globalPosition.dx,
|
||||||
|
_startHandleDragPosition + _startHandleDragPositionToCenterOfLine,
|
||||||
|
);
|
||||||
|
final TextPosition position = renderObject.getPositionForPoint(adjustedOffset);
|
||||||
|
|
||||||
if (_selection.isCollapsed) {
|
if (_selection.isCollapsed) {
|
||||||
_selectionOverlay.updateMagnifier(_buildMagnifier(
|
_selectionOverlay.updateMagnifier(_buildMagnifier(
|
||||||
@ -753,7 +804,8 @@ class TextSelectionOverlay {
|
|||||||
renderEditable: renderObject,
|
renderEditable: renderObject,
|
||||||
));
|
));
|
||||||
|
|
||||||
_handleSelectionHandleChanged(TextSelection.fromPosition(position), isEnd: false);
|
final TextSelection currentSelection = TextSelection.fromPosition(position);
|
||||||
|
_handleSelectionHandleChanged(currentSelection, isEnd: false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,32 +865,6 @@ class TextSelectionOverlay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the offset that locates a drag on a handle to the correct line of text.
|
|
||||||
Offset _getOffsetToTextPositionPoint(TextSelectionHandleType type) {
|
|
||||||
final Size handleSize = selectionControls!.getHandleSize(
|
|
||||||
renderObject.preferredLineHeight,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Try to shift center of handle to top by half of handle height.
|
|
||||||
final double halfHandleHeight = handleSize.height / 2;
|
|
||||||
|
|
||||||
// [getHandleAnchor] is used to shift the selection endpoint to the top left
|
|
||||||
// point of the handle rect when building the handle widget.
|
|
||||||
// The endpoint is at the bottom of the selection rect, which is also at the
|
|
||||||
// bottom of the line of text.
|
|
||||||
// Try to shift the top of the handle to the selection endpoint by the dy of
|
|
||||||
// the handle's anchor.
|
|
||||||
final double handleAnchorDy = selectionControls!.getHandleAnchor(type, renderObject.preferredLineHeight).dy;
|
|
||||||
|
|
||||||
// Try to shift the selection endpoint to the center of the correct line by
|
|
||||||
// using half of the line height.
|
|
||||||
final double halfPreferredLineHeight = renderObject.preferredLineHeight / 2;
|
|
||||||
|
|
||||||
// The x offset is accurate, so we only need to adjust the y position.
|
|
||||||
final double offsetYFromHandleToTextPosition = handleAnchorDy - halfHandleHeight - halfPreferredLineHeight;
|
|
||||||
return Offset(0.0, offsetYFromHandleToTextPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleSelectionHandleChanged(TextSelection newSelection, {required bool isEnd}) {
|
void _handleSelectionHandleChanged(TextSelection newSelection, {required bool isEnd}) {
|
||||||
final TextPosition textPosition = isEnd ? newSelection.extent : newSelection.base;
|
final TextPosition textPosition = isEnd ? newSelection.extent : newSelection.base;
|
||||||
selectionDelegate.userUpdateTextEditingValue(
|
selectionDelegate.userUpdateTextEditingValue(
|
||||||
|
@ -3452,6 +3452,385 @@ void main() {
|
|||||||
expect(controller.selection.extentOffset, 5);
|
expect(controller.selection.extentOffset, 5);
|
||||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
|
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
|
||||||
|
|
||||||
|
testWidgets('Dragging between multiple lines keeps the contact point at the same place on the handle on Android', (WidgetTester tester) async {
|
||||||
|
final TextEditingController controller = TextEditingController(
|
||||||
|
// 11 first line, 19 second line, 17 third line = length 49
|
||||||
|
text: 'a big house\njumped over a mouse\nOne more line yay',
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
CupertinoApp(
|
||||||
|
home: Center(
|
||||||
|
child: CupertinoTextField(
|
||||||
|
dragStartBehavior: DragStartBehavior.down,
|
||||||
|
controller: controller,
|
||||||
|
maxLines: 3,
|
||||||
|
minLines: 3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Double tap to select 'over'.
|
||||||
|
final Offset pos = textOffsetToPosition(tester, controller.text.indexOf('v'));
|
||||||
|
// The first tap.
|
||||||
|
TestGesture gesture = await tester.startGesture(pos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
|
||||||
|
|
||||||
|
// The second tap.
|
||||||
|
await gesture.down(pos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
final TextSelection selection = controller.selection;
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 23,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final RenderEditable renderEditable = findRenderEditable(tester);
|
||||||
|
List<TextSelectionPoint> endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
expect(endpoints.length, 2);
|
||||||
|
|
||||||
|
// Drag the right handle 4 letters to the right.
|
||||||
|
// The adjustment moves the tap from the text position to the handle.
|
||||||
|
const Offset endHandleAdjustment = Offset(1.0, 6.0);
|
||||||
|
Offset handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
Offset newHandlePos = textOffsetToPosition(tester, 27) + endHandleAdjustment;
|
||||||
|
await tester.pump();
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the right handle 1 line down.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
final Offset toNextLine = Offset(
|
||||||
|
0.0,
|
||||||
|
findRenderEditable(tester).preferredLineHeight + 3.0,
|
||||||
|
);
|
||||||
|
newHandlePos = handlePos + toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 47,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the right handle back up 1 line.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
newHandlePos = handlePos - toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 4 letters to the left.
|
||||||
|
// The adjustment moves the tap from the text position to the handle.
|
||||||
|
const Offset startHandleAdjustment = Offset(-1.0, 6.0);
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = textOffsetToPosition(tester, 15) + startHandleAdjustment;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 15,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 1 line up.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = handlePos - toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 3,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 1 line back down.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = handlePos + toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 15,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android }),
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets('Dragging between multiple lines keeps the contact point at the same place on the handle on iOS', (WidgetTester tester) async {
|
||||||
|
final TextEditingController controller = TextEditingController(
|
||||||
|
// 11 first line, 19 second line, 17 third line = length 49
|
||||||
|
text: 'a big house\njumped over a mouse\nOne more line yay',
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
CupertinoApp(
|
||||||
|
home: Center(
|
||||||
|
child: CupertinoTextField(
|
||||||
|
dragStartBehavior: DragStartBehavior.down,
|
||||||
|
controller: controller,
|
||||||
|
maxLines: 3,
|
||||||
|
minLines: 3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Double tap to select 'over'.
|
||||||
|
final Offset pos = textOffsetToPosition(tester, controller.text.indexOf('v'));
|
||||||
|
// The first tap.
|
||||||
|
TestGesture gesture = await tester.startGesture(pos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
|
||||||
|
|
||||||
|
// The second tap.
|
||||||
|
await gesture.down(pos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
final TextSelection selection = controller.selection;
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 23,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final RenderEditable renderEditable = findRenderEditable(tester);
|
||||||
|
List<TextSelectionPoint> endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
expect(endpoints.length, 2);
|
||||||
|
|
||||||
|
// Drag the right handle 4 letters to the right.
|
||||||
|
// The adjustment moves the tap from the text position to the handle.
|
||||||
|
const Offset endHandleAdjustment = Offset(1.0, 6.0);
|
||||||
|
Offset handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
Offset newHandlePos = textOffsetToPosition(tester, 27) + endHandleAdjustment;
|
||||||
|
await tester.pump();
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the right handle 1 line down.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
final double lineHeight = findRenderEditable(tester).preferredLineHeight;
|
||||||
|
final Offset toNextLine = Offset(0.0, lineHeight + 3.0);
|
||||||
|
newHandlePos = handlePos + toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 47,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the right handle back up 1 line.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
newHandlePos = handlePos - toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 4 letters to the left.
|
||||||
|
// The adjustment moves the tap from the text position to the handle.
|
||||||
|
final Offset startHandleAdjustment = Offset(-1.0, -lineHeight + 6.0);
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = textOffsetToPosition(tester, 15) + startHandleAdjustment;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// On Apple platforms, dragging the base handle makes it the extent.
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 27,
|
||||||
|
extentOffset: 15,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 1 line up.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = handlePos - toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 27,
|
||||||
|
extentOffset: 3,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 1 line back down.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = handlePos + toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 27,
|
||||||
|
extentOffset: 15,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
|
||||||
|
);
|
||||||
|
|
||||||
testWidgets('Selection updates on tap down (Desktop platforms)', (WidgetTester tester) async {
|
testWidgets('Selection updates on tap down (Desktop platforms)', (WidgetTester tester) async {
|
||||||
final TextEditingController controller = TextEditingController();
|
final TextEditingController controller = TextEditingController();
|
||||||
|
|
||||||
|
@ -2537,6 +2537,381 @@ void main() {
|
|||||||
expect(controller.selection.extentOffset, 5);
|
expect(controller.selection.extentOffset, 5);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Dragging between multiple lines keeps the contact point at the same place on the handle on Android', (WidgetTester tester) async {
|
||||||
|
final TextEditingController controller = TextEditingController(
|
||||||
|
// 11 first line, 19 second line, 17 third line = length 49
|
||||||
|
text: 'a big house\njumped over a mouse\nOne more line yay',
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
overlay(
|
||||||
|
child: TextField(
|
||||||
|
dragStartBehavior: DragStartBehavior.down,
|
||||||
|
controller: controller,
|
||||||
|
maxLines: 3,
|
||||||
|
minLines: 3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Double tap to select 'over'.
|
||||||
|
final Offset pos = textOffsetToPosition(tester, controller.text.indexOf('v'));
|
||||||
|
// The first tap.
|
||||||
|
TestGesture gesture = await tester.startGesture(pos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
|
||||||
|
|
||||||
|
// The second tap.
|
||||||
|
await gesture.down(pos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
final TextSelection selection = controller.selection;
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 23,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final RenderEditable renderEditable = findRenderEditable(tester);
|
||||||
|
List<TextSelectionPoint> endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
expect(endpoints.length, 2);
|
||||||
|
|
||||||
|
// Drag the right handle 4 letters to the right.
|
||||||
|
// The adjustment moves the tap from the text position to the handle.
|
||||||
|
const Offset endHandleAdjustment = Offset(1.0, 6.0);
|
||||||
|
Offset handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
Offset newHandlePos = textOffsetToPosition(tester, 27) + endHandleAdjustment;
|
||||||
|
await tester.pump();
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the right handle 1 line down.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
final Offset toNextLine = Offset(
|
||||||
|
0.0,
|
||||||
|
findRenderEditable(tester).preferredLineHeight + 3.0,
|
||||||
|
);
|
||||||
|
newHandlePos = handlePos + toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 47,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the right handle back up 1 line.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
newHandlePos = handlePos - toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 4 letters to the left.
|
||||||
|
// The adjustment moves the tap from the text position to the handle.
|
||||||
|
const Offset startHandleAdjustment = Offset(-1.0, 6.0);
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = textOffsetToPosition(tester, 15) + startHandleAdjustment;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 15,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 1 line up.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = handlePos - toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 3,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 1 line back down.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = handlePos + toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 15,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android }),
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets('Dragging between multiple lines keeps the contact point at the same place on the handle on iOS', (WidgetTester tester) async {
|
||||||
|
final TextEditingController controller = TextEditingController(
|
||||||
|
// 11 first line, 19 second line, 17 third line = length 49
|
||||||
|
text: 'a big house\njumped over a mouse\nOne more line yay',
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
overlay(
|
||||||
|
child: TextField(
|
||||||
|
dragStartBehavior: DragStartBehavior.down,
|
||||||
|
controller: controller,
|
||||||
|
maxLines: 3,
|
||||||
|
minLines: 3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Double tap to select 'over'.
|
||||||
|
final Offset pos = textOffsetToPosition(tester, controller.text.indexOf('v'));
|
||||||
|
// The first tap.
|
||||||
|
TestGesture gesture = await tester.startGesture(pos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
|
||||||
|
|
||||||
|
// The second tap.
|
||||||
|
await gesture.down(pos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
final TextSelection selection = controller.selection;
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 23,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final RenderEditable renderEditable = findRenderEditable(tester);
|
||||||
|
List<TextSelectionPoint> endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
expect(endpoints.length, 2);
|
||||||
|
|
||||||
|
// Drag the right handle 4 letters to the right.
|
||||||
|
// The adjustment moves the tap from the text position to the handle.
|
||||||
|
const Offset endHandleAdjustment = Offset(1.0, 6.0);
|
||||||
|
Offset handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
Offset newHandlePos = textOffsetToPosition(tester, 27) + endHandleAdjustment;
|
||||||
|
await tester.pump();
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the right handle 1 line down.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
final double lineHeight = findRenderEditable(tester).preferredLineHeight;
|
||||||
|
final Offset toNextLine = Offset(0.0, lineHeight + 3.0);
|
||||||
|
newHandlePos = handlePos + toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 47,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the right handle back up 1 line.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[1].point + endHandleAdjustment;
|
||||||
|
newHandlePos = handlePos - toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 19,
|
||||||
|
extentOffset: 27,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 4 letters to the left.
|
||||||
|
// The adjustment moves the tap from the text position to the handle.
|
||||||
|
final Offset startHandleAdjustment = Offset(-1.0, -lineHeight + 6.0);
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = textOffsetToPosition(tester, 15) + startHandleAdjustment;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// On Apple platforms, dragging the base handle makes it the extent.
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 27,
|
||||||
|
extentOffset: 15,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 1 line up.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = handlePos - toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 27,
|
||||||
|
extentOffset: 3,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drag the left handle 1 line back down.
|
||||||
|
endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(controller.selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
handlePos = endpoints[0].point + startHandleAdjustment;
|
||||||
|
newHandlePos = handlePos + toNextLine;
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 27,
|
||||||
|
extentOffset: 15,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
|
||||||
|
);
|
||||||
|
|
||||||
testWidgets("dragging caret within a word doesn't affect composing region", (WidgetTester tester) async {
|
testWidgets("dragging caret within a word doesn't affect composing region", (WidgetTester tester) async {
|
||||||
const String testValue = 'abc def ghi';
|
const String testValue = 'abc def ghi';
|
||||||
final TextEditingController controller = TextEditingController.fromValue(
|
final TextEditingController controller = TextEditingController.fromValue(
|
||||||
@ -3554,8 +3929,13 @@ void main() {
|
|||||||
await tester.pump();
|
await tester.pump();
|
||||||
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
|
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
|
||||||
|
|
||||||
expect(controller.selection.baseOffset, 39);
|
expect(
|
||||||
expect(controller.selection.extentOffset, 44);
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 39,
|
||||||
|
extentOffset: 44,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
final RenderEditable renderEditable = findRenderEditable(tester);
|
final RenderEditable renderEditable = findRenderEditable(tester);
|
||||||
final List<TextSelectionPoint> endpoints = globalize(
|
final List<TextSelectionPoint> endpoints = globalize(
|
||||||
@ -3566,7 +3946,11 @@ void main() {
|
|||||||
|
|
||||||
// Drag the right handle to the third line, just after 'Third'.
|
// Drag the right handle to the third line, just after 'Third'.
|
||||||
Offset handlePos = endpoints[1].point + const Offset(1.0, 1.0);
|
Offset handlePos = endpoints[1].point + const Offset(1.0, 1.0);
|
||||||
Offset newHandlePos = textOffsetToPosition(tester, testValue.indexOf('Third') + 5);
|
// The distance below the y value returned by textOffsetToPosition required
|
||||||
|
// to register a full vertical line drag.
|
||||||
|
const Offset downLineOffset = Offset(0.0, 3.0);
|
||||||
|
Offset newHandlePos =
|
||||||
|
textOffsetToPosition(tester, testValue.indexOf('Third') + 5) + downLineOffset;
|
||||||
gesture = await tester.startGesture(handlePos, pointer: 7);
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
await gesture.moveTo(newHandlePos);
|
await gesture.moveTo(newHandlePos);
|
||||||
@ -3574,8 +3958,13 @@ void main() {
|
|||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
||||||
expect(controller.selection.baseOffset, 39);
|
expect(
|
||||||
expect(controller.selection.extentOffset, 50);
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 39,
|
||||||
|
extentOffset: 50,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// Drag the left handle to the first line, just after 'First'.
|
// Drag the left handle to the first line, just after 'First'.
|
||||||
handlePos = endpoints[0].point + const Offset(-1.0, 1.0);
|
handlePos = endpoints[0].point + const Offset(-1.0, 1.0);
|
||||||
|
@ -1213,7 +1213,11 @@ void main() {
|
|||||||
|
|
||||||
// Drag the right handle to the third line, just after 'Third'.
|
// Drag the right handle to the third line, just after 'Third'.
|
||||||
Offset handlePos = endpoints[1].point + const Offset(1.0, 1.0);
|
Offset handlePos = endpoints[1].point + const Offset(1.0, 1.0);
|
||||||
Offset newHandlePos = textOffsetToPosition(tester, testValue.indexOf('Third') + 5);
|
// The distance below the y value returned by textOffsetToPosition required
|
||||||
|
// to register a full vertical line drag.
|
||||||
|
const Offset downLineOffset = Offset(0.0, 3.0);
|
||||||
|
Offset newHandlePos =
|
||||||
|
textOffsetToPosition(tester, testValue.indexOf('Third') + 5) + downLineOffset;
|
||||||
gesture = await tester.startGesture(handlePos, pointer: 7);
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
await gesture.moveTo(newHandlePos);
|
await gesture.moveTo(newHandlePos);
|
||||||
@ -1221,8 +1225,13 @@ void main() {
|
|||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
||||||
expect(controller.selection.baseOffset, 39);
|
expect(
|
||||||
expect(controller.selection.extentOffset, 50);
|
controller.selection,
|
||||||
|
const TextSelection(
|
||||||
|
baseOffset: 39,
|
||||||
|
extentOffset: 50,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// Drag the left handle to the first line, just after 'First'.
|
// Drag the left handle to the first line, just after 'First'.
|
||||||
handlePos = endpoints[0].point + const Offset(-1.0, 1.0);
|
handlePos = endpoints[0].point + const Offset(-1.0, 1.0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user