mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fix crash when disposing nested Scrollables while holding in overscroll position (#27864)
This commit is contained in:
parent
964fab0205
commit
aa8f86135d
@ -53,10 +53,12 @@ abstract class Notification {
|
||||
///
|
||||
/// The notification will be delivered to any [NotificationListener] widgets
|
||||
/// with the appropriate type parameters that are ancestors of the given
|
||||
/// [BuildContext].
|
||||
/// [BuildContext]. If the [BuildContext] is null, the notification is not
|
||||
/// dispatched.
|
||||
void dispatch(BuildContext target) {
|
||||
assert(target != null); // Only call dispatch if the widget's State is still mounted.
|
||||
target.visitAncestorElements(visitAncestor);
|
||||
// The `target` may be null if the subtree the notification is supposed to be
|
||||
// dispatched in is in the process of being disposed.
|
||||
target?.visitAncestorElements(visitAncestor);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
@ -28,4 +30,68 @@ void main() {
|
||||
tester.state<FlipWidgetState>(find.byType(FlipWidget)).flip();
|
||||
await tester.pump(const Duration(hours: 5));
|
||||
});
|
||||
|
||||
testWidgets('Disposing a (nested) Scrollable while holding in overscroll (iOS) does not crash', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/27707.
|
||||
|
||||
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
|
||||
final ScrollController controller = ScrollController();
|
||||
final Key outterContainer = GlobalKey();
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Center(
|
||||
child: Container(
|
||||
key: outterContainer,
|
||||
color: Colors.purple,
|
||||
width: 400.0,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Container(
|
||||
width: 500.0,
|
||||
child: ListView.builder(
|
||||
controller: controller,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return Container(
|
||||
color: index % 2 == 0 ? Colors.red : Colors.green,
|
||||
height: 200.0,
|
||||
child: Text('Hello $index'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Go into overscroll.
|
||||
double lastScrollOffset;
|
||||
await tester.fling(find.text('Hello 0'), const Offset(0.0, 1000.0), 1000.0);
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
expect(lastScrollOffset = controller.offset, lessThan(0.0));
|
||||
|
||||
// Reduce the overscroll a little, but don't let it go back to 0.0.
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
expect(controller.offset, greaterThan(lastScrollOffset));
|
||||
expect(controller.offset, lessThan(0.0));
|
||||
final double currentOffset = controller.offset;
|
||||
|
||||
// Start a hold activity by putting one pointer down.
|
||||
await tester.startGesture(tester.getTopLeft(find.byKey(outterContainer)) + const Offset(50.0, 50.0));
|
||||
await tester.pumpAndSettle(); // This shouldn't change the scroll offset because of the down event above.
|
||||
expect(controller.offset, currentOffset);
|
||||
|
||||
// Dispose the scrollables while the finger is still down, this should not crash.
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Container(),
|
||||
)
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(controller.hasClients, isFalse);
|
||||
|
||||
debugDefaultTargetPlatformOverride = null;
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user