Unverified Commit 511020ac authored by Viren Khatri's avatar Viren Khatri Committed by GitHub

Fixes `RangeError` bug when length of `TabBar.tabs` is changed (#94623)

parent 2a529bc5
......@@ -982,11 +982,11 @@ class _TabBarState extends State<TabBar> {
_initIndicatorPainter();
}
if (widget.tabs.length > oldWidget.tabs.length) {
final int delta = widget.tabs.length - oldWidget.tabs.length;
if (widget.tabs.length > _tabKeys.length) {
final int delta = widget.tabs.length - _tabKeys.length;
_tabKeys.addAll(List<GlobalKey>.generate(delta, (int n) => GlobalKey()));
} else if (widget.tabs.length < oldWidget.tabs.length) {
_tabKeys.removeRange(widget.tabs.length, oldWidget.tabs.length);
} else if (widget.tabs.length < _tabKeys.length) {
_tabKeys.removeRange(widget.tabs.length, _tabKeys.length);
}
}
......
......@@ -3136,6 +3136,7 @@ void main() {
},
);
});
testWidgets('Skipping tabs with global key does not crash', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/24660
final List<String> tabs = <String>[
......@@ -3433,9 +3434,9 @@ void main() {
title: const Text('Default TabBar Preview'),
bottom: tabTextContent.isNotEmpty
? TabBar(
isScrollable: true,
tabs: tabTextContent.map((String textContent) => Tab(text: textContent)).toList(),
)
isScrollable: true,
tabs: tabTextContent.map((String textContent) => Tab(text: textContent)).toList(),
)
: null,
),
body: tabTextContent.isNotEmpty
......@@ -3490,31 +3491,96 @@ void main() {
expect(find.text('No tabs'), findsOneWidget);
});
testWidgets('DefaultTabController should allow dynamic length of tabs', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/94504.
final List<String> tabTitles = <String>[];
void _onTabAdd(StateSetter setState) {
setState(() {
tabTitles.add('Tab ${tabTitles.length + 1}');
});
}
void _onTabRemove(StateSetter setState) {
setState(() {
tabTitles.removeLast();
});
}
await tester.pumpWidget(
MaterialApp(
home: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return DefaultTabController(
length: tabTitles.length,
child: Scaffold(
appBar: AppBar(
actions: <Widget>[
TextButton(
key: const Key('Add tab'),
child: const Text('Add tab'),
onPressed: () => _onTabAdd(setState),
),
TextButton(
key: const Key('Remove tab'),
child: const Text('Remove tab'),
onPressed: () => _onTabRemove(setState),
),
],
bottom: PreferredSize(
preferredSize: const Size.fromHeight(40.0),
child: Expanded(
child: TabBar(
tabs: tabTitles
.map((String title) => Tab(text: title))
.toList(),
),
),
),
),
),
);
},
),
),
);
expect(find.text('Tab 1'), findsNothing);
expect(find.text('Tab 2'), findsNothing);
await tester.tap(find.byKey(const Key('Add tab'))); // +1
await tester.pumpAndSettle();
expect(find.text('Tab 1'), findsOneWidget);
expect(find.text('Tab 2'), findsNothing);
await tester.tap(find.byKey(const Key('Add tab'))); // +2
await tester.pumpAndSettle();
expect(find.text('Tab 1'), findsOneWidget);
expect(find.text('Tab 2'), findsOneWidget);
await tester.tap(find.byKey(const Key('Remove tab'))); // -2
await tester.tap(find.byKey(const Key('Remove tab'))); // -1
await tester.pumpAndSettle();
expect(find.text('Tab 1'), findsNothing);
expect(find.text('Tab 2'), findsNothing);
});
testWidgets('TabBar - updating to and from zero tabs', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/68962.
final List<String> tabTitles = <String>[];
final List<Widget> tabContents = <Widget>[];
TabController _tabController = TabController(length: tabContents.length, vsync: const TestVSync());
TabController _tabController = TabController(length: tabTitles.length, vsync: const TestVSync());
void _onTabAdd(StateSetter setState) {
setState(() {
tabTitles.add('Tab ${tabTitles.length + 1}');
tabContents.add(
Container(
color: Colors.red,
height: 200,
width: 200,
),
);
_tabController = TabController(length: tabContents.length, vsync: const TestVSync());
_tabController = TabController(length: tabTitles.length, vsync: const TestVSync());
});
}
void _onTabRemove(StateSetter setState) {
setState(() {
tabTitles.removeLast();
tabContents.removeLast();
_tabController = TabController(length: tabContents.length, vsync: const TestVSync());
_tabController = TabController(length: tabTitles.length, vsync: const TestVSync());
});
}
......
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