Unverified Commit d841d321 authored by Bruno Leroux's avatar Bruno Leroux Committed by GitHub

TabBar should adjust scroll position when Controller is changed (#116019)

Co-authored-by: 's avatarBruno Leroux <bruno.leroux@gmail.com>
parent 2703a2bc
......@@ -519,26 +519,35 @@ class _TabBarScrollPosition extends ScrollPositionWithSingleContext {
final _TabBarState tabBar;
bool? _initialViewportDimensionWasZero;
bool _viewportDimensionWasNonZero = false;
// Position should be adjusted at least once.
bool _needsPixelsCorrection = true;
@override
bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) {
bool result = true;
if (_initialViewportDimensionWasZero != true) {
// If the viewport never had a non-zero dimension, we just want to jump
// to the initial scroll position to avoid strange scrolling effects in
// release mode: In release mode, the viewport temporarily may have a
// dimension of zero before the actual dimension is calculated. In that
// scenario, setting the actual dimension would cause a strange scroll
// effect without this guard because the super call below would starts a
// ballistic scroll activity.
assert(viewportDimension != null);
_initialViewportDimensionWasZero = viewportDimension != 0.0;
if (!_viewportDimensionWasNonZero) {
_viewportDimensionWasNonZero = viewportDimension != 0.0;
}
// If the viewport never had a non-zero dimension, we just want to jump
// to the initial scroll position to avoid strange scrolling effects in
// release mode: In release mode, the viewport temporarily may have a
// dimension of zero before the actual dimension is calculated. In that
// scenario, setting the actual dimension would cause a strange scroll
// effect without this guard because the super call below would starts a
// ballistic scroll activity.
if (!_viewportDimensionWasNonZero || _needsPixelsCorrection) {
_needsPixelsCorrection = false;
correctPixels(tabBar._initialScrollOffset(viewportDimension, minScrollExtent, maxScrollExtent));
result = false;
}
return super.applyContentDimensions(minScrollExtent, maxScrollExtent) && result;
}
void markNeedsPixelsCorrection() {
_needsPixelsCorrection = true;
}
}
// This class, and TabBarScrollPosition, only exist to handle the case
......@@ -1027,6 +1036,13 @@ class _TabBarState extends State<TabBar> {
if (widget.controller != oldWidget.controller) {
_updateTabController();
_initIndicatorPainter();
// Adjust scroll position.
if (_scrollController != null) {
final ScrollPosition position = _scrollController!.position;
if (position is _TabBarScrollPosition) {
position.markNeedsPixelsCorrection();
}
}
} else if (widget.indicatorColor != oldWidget.indicatorColor ||
widget.indicatorWeight != oldWidget.indicatorWeight ||
widget.indicatorSize != oldWidget.indicatorSize ||
......
......@@ -3420,6 +3420,49 @@ void main() {
));
});
testWidgets('TabController changes with different initialIndex', (WidgetTester tester) async {
// This is a regression test for https://github.com/flutter/flutter/issues/115917
const Key lastTabKey = Key('Last Tab');
TabController? controller;
Widget buildFrame(int length) {
controller = TabController(
vsync: const TestVSync(),
length: length,
initialIndex: length - 1,
);
return boilerplate(
child: TabBar(
labelPadding: EdgeInsets.zero,
controller: controller,
isScrollable: true,
tabs: List<Widget>.generate(
length,
(int index) {
return SizedBox(
width: 100,
child: Tab(
key: index == length - 1 ? lastTabKey : null,
text: 'Tab $index',
),
);
},
),
),
);
}
await tester.pumpWidget(buildFrame(10));
expect(controller!.index, 9);
expect(tester.getCenter(find.byKey(lastTabKey)).dx, equals(750.0));
// Rebuild with a new controller with more tabs and last tab selected.
// Last tab should be visible and on the right of the window.
await tester.pumpWidget(buildFrame(15));
expect(controller!.index, 14);
expect(tester.getCenter(find.byKey(lastTabKey)).dx, equals(750.0));
});
testWidgets('Default tab indicator color is white', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/15958
final List<String> tabs = <String>['LEFT', 'RIGHT'];
......
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