Make dpr available during Scrollable disposal (#126535)
Fixes https://github.com/flutter/flutter/issues/126454. In certain situations (see linked bug) the Scrollable needs access to the DPR of the View it is drawn into during disposal. Since inherited widget lookups are not allowed during disposal, we cannot look up the DPR dynamically in these situations. Instead, we have to cache the DPR when lookups are still allowed.
This commit is contained in:
committed by
GitHub
parent
12659f2a7b
commit
dc3d6603f2
@@ -42,6 +42,10 @@ abstract class ScrollContext {
|
||||
/// The direction in which the widget scrolls.
|
||||
AxisDirection get axisDirection;
|
||||
|
||||
/// The [FlutterView.devicePixelRatio] of the view that the [Scrollable] this
|
||||
/// [ScrollContext] is associated with is drawn into.
|
||||
double get devicePixelRatio;
|
||||
|
||||
/// Whether the contents of the widget should ignore [PointerEvent] inputs.
|
||||
///
|
||||
/// Setting this value to true prevents the use from interacting with the
|
||||
|
||||
@@ -12,7 +12,6 @@ import 'package:flutter/scheduler.dart';
|
||||
|
||||
import 'basic.dart';
|
||||
import 'framework.dart';
|
||||
import 'media_query.dart';
|
||||
import 'notification_listener.dart';
|
||||
import 'page_storage.dart';
|
||||
import 'scroll_activity.dart';
|
||||
@@ -20,7 +19,6 @@ import 'scroll_context.dart';
|
||||
import 'scroll_metrics.dart';
|
||||
import 'scroll_notification.dart';
|
||||
import 'scroll_physics.dart';
|
||||
import 'view.dart';
|
||||
|
||||
export 'scroll_activity.dart' show ScrollHoldController;
|
||||
|
||||
@@ -241,7 +239,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
|
||||
}
|
||||
|
||||
@override
|
||||
double get devicePixelRatio => MediaQuery.maybeDevicePixelRatioOf(context.storageContext) ?? View.of(context.storageContext).devicePixelRatio;
|
||||
double get devicePixelRatio => context.devicePixelRatio;
|
||||
|
||||
/// Update the scroll position ([pixels]) to a given pixel value.
|
||||
///
|
||||
|
||||
@@ -28,6 +28,7 @@ import 'scrollable_helpers.dart';
|
||||
import 'selectable_region.dart';
|
||||
import 'selection_container.dart';
|
||||
import 'ticker_provider.dart';
|
||||
import 'view.dart';
|
||||
import 'viewport.dart';
|
||||
|
||||
export 'package:flutter/physics.dart' show Tolerance;
|
||||
@@ -530,6 +531,10 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
|
||||
@override
|
||||
TickerProvider get vsync => this;
|
||||
|
||||
@override
|
||||
double get devicePixelRatio => _devicePixelRatio;
|
||||
late double _devicePixelRatio;
|
||||
|
||||
@override
|
||||
BuildContext? get notificationContext => _gestureDetectorKey.currentContext;
|
||||
|
||||
@@ -596,6 +601,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
_mediaQueryGestureSettings = MediaQuery.maybeGestureSettingsOf(context);
|
||||
_devicePixelRatio = MediaQuery.maybeDevicePixelRatioOf(context) ?? View.of(context).devicePixelRatio;
|
||||
_updatePosition();
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
@@ -980,7 +986,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(DiagnosticsProperty<ScrollPosition>('position', position));
|
||||
properties.add(DiagnosticsProperty<ScrollPosition>('position', _position));
|
||||
properties.add(DiagnosticsProperty<ScrollPhysics>('effective physics', _physics));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2871,6 +2871,43 @@ void main() {
|
||||
expect(appBarHeight(tester), expandedAppBarHeight);
|
||||
expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight);
|
||||
});
|
||||
|
||||
testWidgets('NestedScrollView does not crash when inner scrollable changes while scrolling', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/126454.
|
||||
Widget buildApp({required bool nested}) {
|
||||
final Widget innerScrollable = ListView(
|
||||
children: const <Widget>[SizedBox(height: 1000)],
|
||||
);
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: NestedScrollView(
|
||||
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||
return <Widget>[
|
||||
SliverAppBar(
|
||||
title: const Text('Books'),
|
||||
pinned: true,
|
||||
expandedHeight: 150.0,
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
),
|
||||
];
|
||||
},
|
||||
body: nested ? Container(child: innerScrollable) : innerScrollable,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildApp(nested: false));
|
||||
|
||||
// Start a scroll.
|
||||
final TestGesture scrollDrag = await tester.startGesture(tester.getCenter(find.byType(ListView)));
|
||||
await tester.pump();
|
||||
await scrollDrag.moveBy(const Offset(0, 50));
|
||||
await tester.pump();
|
||||
|
||||
// Restructuring inner scrollable while scroll is in progress shouldn't crash.
|
||||
await tester.pumpWidget(buildApp(nested: true));
|
||||
});
|
||||
}
|
||||
|
||||
double appBarHeight(WidgetTester tester) => tester.getSize(find.byType(AppBar, skipOffstage: false)).height;
|
||||
|
||||
Reference in New Issue
Block a user