mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Make disposing a ScrollPosition with pixels=null legal (#44617)
This commit is contained in:
parent
a872a701c3
commit
bcc93bca23
@ -333,29 +333,6 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
|
|||||||
final int initialPage;
|
final int initialPage;
|
||||||
double _pageToUseOnStartup;
|
double _pageToUseOnStartup;
|
||||||
|
|
||||||
/// If [pixels] isn't set by [applyViewportDimension] before [dispose] is
|
|
||||||
/// called, this could throw an assert as [pixels] will be set to null.
|
|
||||||
///
|
|
||||||
/// With [Tab]s, this happens when there are nested [TabBarView]s and there
|
|
||||||
/// is an attempt to warp over the nested tab to a tab adjacent to it.
|
|
||||||
///
|
|
||||||
/// This flag will be set to true once the dimensions have been established
|
|
||||||
/// and [pixels] is set.
|
|
||||||
bool isInitialPixelsValueSet = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
// TODO(shihaohong): remove workaround once these issues have been
|
|
||||||
// resolved, https://github.com/flutter/flutter/issues/32054,
|
|
||||||
// https://github.com/flutter/flutter/issues/32056
|
|
||||||
// Sets `pixels` to a non-null value before `ScrollPosition.dispose` is
|
|
||||||
// invoked if it was never set by `applyViewportDimension`.
|
|
||||||
if (pixels == null && !isInitialPixelsValueSet) {
|
|
||||||
correctPixels(0);
|
|
||||||
}
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double get viewportFraction => _viewportFraction;
|
double get viewportFraction => _viewportFraction;
|
||||||
double _viewportFraction;
|
double _viewportFraction;
|
||||||
@ -422,7 +399,6 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
|
|||||||
|
|
||||||
if (newPixels != oldPixels) {
|
if (newPixels != oldPixels) {
|
||||||
correctPixels(newPixels);
|
correctPixels(newPixels);
|
||||||
isInitialPixelsValueSet = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -693,7 +693,6 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
assert(pixels != null);
|
|
||||||
activity?.dispose(); // it will be null if it got absorbed by another ScrollPosition
|
activity?.dispose(); // it will be null if it got absorbed by another ScrollPosition
|
||||||
_activity = null;
|
_activity = null;
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
@ -978,8 +978,7 @@ void main() {
|
|||||||
expect(tabController.index, 0);
|
expect(tabController.index, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Nested TabBarView sets ScrollController pixels to non-null value '
|
testWidgets('Can switch to non-neighboring tab in nested TabBarView without crashing', (WidgetTester tester) async {
|
||||||
'when disposed before it is set by the applyViewportDimension', (WidgetTester tester) async {
|
|
||||||
// This is a regression test for https://github.com/flutter/flutter/issues/18756
|
// This is a regression test for https://github.com/flutter/flutter/issues/18756
|
||||||
final TabController _mainTabController = TabController(length: 4, vsync: const TestVSync());
|
final TabController _mainTabController = TabController(length: 4, vsync: const TestVSync());
|
||||||
final TabController _nestedTabController = TabController(length: 2, vsync: const TestVSync());
|
final TabController _nestedTabController = TabController(length: 2, vsync: const TestVSync());
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('Can dispose ScrollPosition when pixels is null', () {
|
||||||
|
final ScrollPosition position = ScrollPositionWithSingleContext(
|
||||||
|
initialPixels: null,
|
||||||
|
keepScrollOffset: false,
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
context: ScrollableState(),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(position.pixels, isNull);
|
||||||
|
position.dispose(); // Should not throw/assert.
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('scrollable in hidden overlay does not crash when unhidden', (WidgetTester tester) async {
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/44269.
|
||||||
|
final TabController controller = TabController(vsync: const TestVSync(), length: 1);
|
||||||
|
|
||||||
|
final OverlayEntry entry1 = OverlayEntry(
|
||||||
|
maintainState: true,
|
||||||
|
opaque: true,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return TabBar(
|
||||||
|
isScrollable: true,
|
||||||
|
controller: controller,
|
||||||
|
tabs: const <Tab>[
|
||||||
|
Tab(text: 'Main'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final OverlayEntry entry2 = OverlayEntry(
|
||||||
|
maintainState: true,
|
||||||
|
opaque: true,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return const Text('number2');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Overlay(
|
||||||
|
initialEntries: <OverlayEntry>[
|
||||||
|
entry1,
|
||||||
|
entry2,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
entry2.remove();
|
||||||
|
await tester.pump();
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user