mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Do not crash when remove SelectableText during handle drag (#108369)
This commit is contained in:
parent
16c25caa44
commit
09b6672e77
@ -444,6 +444,9 @@ class TextSelectionOverlay {
|
|||||||
late Offset _dragEndPosition;
|
late Offset _dragEndPosition;
|
||||||
|
|
||||||
void _handleSelectionEndHandleDragStart(DragStartDetails details) {
|
void _handleSelectionEndHandleDragStart(DragStartDetails details) {
|
||||||
|
if (!renderObject.attached) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final Size handleSize = selectionControls!.getHandleSize(
|
final Size handleSize = selectionControls!.getHandleSize(
|
||||||
renderObject.preferredLineHeight,
|
renderObject.preferredLineHeight,
|
||||||
);
|
);
|
||||||
@ -451,6 +454,9 @@ class TextSelectionOverlay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleSelectionEndHandleDragUpdate(DragUpdateDetails details) {
|
void _handleSelectionEndHandleDragUpdate(DragUpdateDetails details) {
|
||||||
|
if (!renderObject.attached) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
_dragEndPosition += details.delta;
|
_dragEndPosition += details.delta;
|
||||||
final TextPosition position = renderObject.getPositionForPoint(_dragEndPosition);
|
final TextPosition position = renderObject.getPositionForPoint(_dragEndPosition);
|
||||||
|
|
||||||
@ -492,6 +498,9 @@ class TextSelectionOverlay {
|
|||||||
late Offset _dragStartPosition;
|
late Offset _dragStartPosition;
|
||||||
|
|
||||||
void _handleSelectionStartHandleDragStart(DragStartDetails details) {
|
void _handleSelectionStartHandleDragStart(DragStartDetails details) {
|
||||||
|
if (!renderObject.attached) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final Size handleSize = selectionControls!.getHandleSize(
|
final Size handleSize = selectionControls!.getHandleSize(
|
||||||
renderObject.preferredLineHeight,
|
renderObject.preferredLineHeight,
|
||||||
);
|
);
|
||||||
@ -499,6 +508,9 @@ class TextSelectionOverlay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleSelectionStartHandleDragUpdate(DragUpdateDetails details) {
|
void _handleSelectionStartHandleDragUpdate(DragUpdateDetails details) {
|
||||||
|
if (!renderObject.attached) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
_dragStartPosition += details.delta;
|
_dragStartPosition += details.delta;
|
||||||
final TextPosition position = renderObject.getPositionForPoint(_dragStartPosition);
|
final TextPosition position = renderObject.getPositionForPoint(_dragStartPosition);
|
||||||
|
|
||||||
|
@ -176,6 +176,74 @@ void main() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testWidgets('Do not crash when remove SelectableText during handle drag', (WidgetTester tester) async {
|
||||||
|
// Regression test https://github.com/flutter/flutter/issues/108242
|
||||||
|
bool isShow = true;
|
||||||
|
late StateSetter setter;
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
setter = setState;
|
||||||
|
if (isShow) {
|
||||||
|
return const SelectableText(
|
||||||
|
'abc def ghi',
|
||||||
|
dragStartBehavior: DragStartBehavior.down,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final EditableText editableTextWidget = tester.widget(find.byType(EditableText));
|
||||||
|
final TextEditingController controller = editableTextWidget.controller;
|
||||||
|
|
||||||
|
// Long press the 'e' to select 'def'.
|
||||||
|
final Offset ePos = textOffsetToPosition(tester, 5);
|
||||||
|
TestGesture gesture = await tester.startGesture(ePos, pointer: 7);
|
||||||
|
await tester.pump(const Duration(seconds: 2));
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero
|
||||||
|
|
||||||
|
final TextSelection selection = controller.selection;
|
||||||
|
expect(selection.baseOffset, 4);
|
||||||
|
expect(selection.extentOffset, 7);
|
||||||
|
|
||||||
|
final RenderEditable renderEditable = findRenderEditable(tester);
|
||||||
|
final List<TextSelectionPoint> endpoints = globalize(
|
||||||
|
renderEditable.getEndpointsForSelection(selection),
|
||||||
|
renderEditable,
|
||||||
|
);
|
||||||
|
expect(endpoints.length, 2);
|
||||||
|
|
||||||
|
// Drag the left handle to the left.
|
||||||
|
final Offset handlePos = endpoints[0].point + const Offset(-1.0, 1.0);
|
||||||
|
final Offset newHandlePos = textOffsetToPosition(tester, 1);
|
||||||
|
final Offset newHandlePos1 = textOffsetToPosition(tester, 0);
|
||||||
|
gesture = await tester.startGesture(handlePos, pointer: 7);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(newHandlePos);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Unmount the SelectableText during handle drag
|
||||||
|
setter(() {
|
||||||
|
isShow = false;
|
||||||
|
});
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
await gesture.moveTo(newHandlePos1);
|
||||||
|
await tester.pump(); // Do not crash here
|
||||||
|
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('has expected defaults', (WidgetTester tester) async {
|
testWidgets('has expected defaults', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
boilerplate(
|
boilerplate(
|
||||||
|
Loading…
Reference in New Issue
Block a user