| // Copyright 2014 The Flutter 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/material.dart'; |
| |
| /// Flutter code sample for [TabController]. |
| |
| void main() => runApp(const TabControllerExampleApp()); |
| |
| class TabControllerExampleApp extends StatelessWidget { |
| const TabControllerExampleApp({super.key}); |
| |
| static const List<Tab> tabs = <Tab>[ |
| Tab(text: 'Zeroth'), |
| Tab(text: 'First'), |
| Tab(text: 'Second'), |
| ]; |
| |
| @override |
| Widget build(BuildContext context) { |
| return const MaterialApp( |
| home: TabControllerExample(tabs: tabs), |
| ); |
| } |
| } |
| |
| class TabControllerExample extends StatelessWidget { |
| const TabControllerExample({ |
| required this.tabs, |
| super.key, |
| }); |
| |
| final List<Tab> tabs; |
| |
| @override |
| Widget build(BuildContext context) { |
| return DefaultTabController( |
| length: tabs.length, |
| child: DefaultTabControllerListener( |
| onTabChanged: (int index) { |
| debugPrint('tab changed: $index'); |
| }, |
| child: Scaffold( |
| appBar: AppBar( |
| bottom: TabBar(tabs: tabs), |
| ), |
| body: TabBarView( |
| children: tabs.map((Tab tab) { |
| return Center( |
| child: Text( |
| '${tab.text!} Tab', |
| style: Theme.of(context).textTheme.headlineSmall, |
| ), |
| ); |
| }).toList(), |
| ), |
| ), |
| ), |
| ); |
| } |
| } |
| |
| class DefaultTabControllerListener extends StatefulWidget { |
| const DefaultTabControllerListener({ |
| required this.onTabChanged, |
| required this.child, |
| super.key, |
| }); |
| |
| final ValueChanged<int> onTabChanged; |
| |
| final Widget child; |
| |
| @override |
| State<DefaultTabControllerListener> createState() => |
| _DefaultTabControllerListenerState(); |
| } |
| |
| class _DefaultTabControllerListenerState |
| extends State<DefaultTabControllerListener> { |
| TabController? _controller; |
| |
| @override |
| void didChangeDependencies() { |
| super.didChangeDependencies(); |
| |
| final TabController? defaultTabController = |
| DefaultTabController.maybeOf(context); |
| |
| assert(() { |
| if (defaultTabController == null) { |
| throw FlutterError( |
| 'No DefaultTabController for ${widget.runtimeType}.\n' |
| 'When creating a ${widget.runtimeType}, you must ensure that there ' |
| 'is a DefaultTabController above the ${widget.runtimeType}.', |
| ); |
| } |
| return true; |
| }()); |
| |
| if (defaultTabController != _controller) { |
| _controller?.removeListener(_listener); |
| _controller = defaultTabController; |
| _controller?.addListener(_listener); |
| } |
| } |
| |
| void _listener() { |
| final TabController? controller = _controller; |
| |
| if (controller == null || controller.indexIsChanging) { |
| return; |
| } |
| |
| widget.onTabChanged(controller.index); |
| } |
| |
| @override |
| void dispose() { |
| _controller?.removeListener(_listener); |
| super.dispose(); |
| } |
| |
| @override |
| Widget build(BuildContext context) { |
| return widget.child; |
| } |
| } |