Unverified Commit 765fbe66 authored by xubaolin's avatar xubaolin Committed by GitHub

Fix a scrollbar crash bug (#92657)

parent f51b9090
...@@ -607,6 +607,8 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -607,6 +607,8 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
return _paintScrollbar(canvas, size, thumbExtent, _lastAxisDirection!); return _paintScrollbar(canvas, size, thumbExtent, _lastAxisDirection!);
} }
bool get _lastMetricsAreScrollable => _lastMetrics!.minScrollExtent != _lastMetrics!.maxScrollExtent;
/// Same as hitTest, but includes some padding when the [PointerEvent] is /// Same as hitTest, but includes some padding when the [PointerEvent] is
/// caused by [PointerDeviceKind.touch] to make sure that the region /// caused by [PointerDeviceKind.touch] to make sure that the region
/// isn't too small to be interacted with by the user. /// isn't too small to be interacted with by the user.
...@@ -617,12 +619,16 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -617,12 +619,16 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
/// based on proximity. When `forHover` is true, the larger hit test area will /// based on proximity. When `forHover` is true, the larger hit test area will
/// be used. /// be used.
bool hitTestInteractive(Offset position, PointerDeviceKind kind, { bool forHover = false }) { bool hitTestInteractive(Offset position, PointerDeviceKind kind, { bool forHover = false }) {
if (_thumbRect == null) { if (_trackRect == null) {
// We have not computed the scrollbar position yet. // We have not computed the scrollbar position yet.
return false; return false;
} }
final Rect interactiveRect = _trackRect ?? _thumbRect!; if (!_lastMetricsAreScrollable) {
return false;
}
final Rect interactiveRect = _trackRect!;
final Rect paddedRect = interactiveRect.expandToInclude( final Rect paddedRect = interactiveRect.expandToInclude(
Rect.fromCircle(center: _thumbRect!.center, radius: _kMinInteractiveSize / 2), Rect.fromCircle(center: _thumbRect!.center, radius: _kMinInteractiveSize / 2),
); );
...@@ -658,6 +664,10 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -658,6 +664,10 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
return false; return false;
} }
if (!_lastMetricsAreScrollable) {
return false;
}
switch (kind) { switch (kind) {
case PointerDeviceKind.touch: case PointerDeviceKind.touch:
final Rect touchThumbRect = _thumbRect!.expandToInclude( final Rect touchThumbRect = _thumbRect!.expandToInclude(
...@@ -682,6 +692,11 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -682,6 +692,11 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
if (fadeoutOpacityAnimation.value == 0.0) { if (fadeoutOpacityAnimation.value == 0.0) {
return false; return false;
} }
if (!_lastMetricsAreScrollable) {
return false;
}
return _thumbRect!.contains(position!); return _thumbRect!.contains(position!);
} }
...@@ -1347,6 +1362,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -1347,6 +1362,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
void _updateScrollPosition(Offset updatedOffset) { void _updateScrollPosition(Offset updatedOffset) {
assert(_currentController != null); assert(_currentController != null);
assert(_dragScrollbarAxisOffset != null); assert(_dragScrollbarAxisOffset != null);
final ScrollPosition position = _currentController!.position; final ScrollPosition position = _currentController!.position;
late double primaryDelta; late double primaryDelta;
switch (position.axisDirection) { switch (position.axisDirection) {
......
...@@ -2038,6 +2038,43 @@ void main() { ...@@ -2038,6 +2038,43 @@ void main() {
expect(depths[1], 0); expect(depths[1], 0);
}); });
// Regression test for https://github.com/flutter/flutter/issues/92262
testWidgets('Do not crash when resize from scrollable to non-scrollable.', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController();
Widget buildFrame(double height) {
return Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(),
child: RawScrollbar(
controller: scrollController,
interactive: true,
isAlwaysShown: true,
child: SingleChildScrollView(
controller: scrollController,
child: Container(
width: 100.0,
height: height,
color: const Color(0xFF000000),
),
),
),
),
);
}
await tester.pumpWidget(buildFrame(700.0));
await tester.pumpAndSettle();
await tester.pumpWidget(buildFrame(600.0));
await tester.pumpAndSettle();
// Try to drag the thumb.
final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(798.0, 5.0));
await tester.pumpAndSettle();
await dragScrollbarGesture.moveBy(const Offset(0.0, 5.0));
await tester.pumpAndSettle();
});
test('ScrollbarPainter.shouldRepaint returns true when any of the properties changes', () { test('ScrollbarPainter.shouldRepaint returns true when any of the properties changes', () {
ScrollbarPainter createPainter({ ScrollbarPainter createPainter({
Color color = const Color(0xFF000000), Color color = const Color(0xFF000000),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment