// 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'; import '../../gallery/demo.dart'; enum TabsDemoStyle { iconsAndText, iconsOnly, textOnly } class _Page { const _Page({this.icon, this.text}); final IconData? icon; final String? text; } const List<_Page> _allPages = <_Page>[ _Page(icon: Icons.grade, text: 'TRIUMPH'), _Page(icon: Icons.playlist_add, text: 'NOTE'), _Page(icon: Icons.check_circle, text: 'SUCCESS'), _Page(icon: Icons.question_answer, text: 'OVERSTATE'), _Page(icon: Icons.sentiment_very_satisfied, text: 'SATISFACTION'), _Page(icon: Icons.camera, text: 'APERTURE'), _Page(icon: Icons.assignment_late, text: 'WE MUST'), _Page(icon: Icons.assignment_turned_in, text: 'WE CAN'), _Page(icon: Icons.group, text: 'ALL'), _Page(icon: Icons.block, text: 'EXCEPT'), _Page(icon: Icons.sentiment_very_dissatisfied, text: 'CRYING'), _Page(icon: Icons.error, text: 'MISTAKE'), _Page(icon: Icons.loop, text: 'TRYING'), _Page(icon: Icons.cake, text: 'CAKE'), ]; class ScrollableTabsDemo extends StatefulWidget { const ScrollableTabsDemo({super.key}); static const String routeName = '/material/scrollable-tabs'; @override ScrollableTabsDemoState createState() => ScrollableTabsDemoState(); } class ScrollableTabsDemoState extends State with SingleTickerProviderStateMixin { TabController? _controller; TabsDemoStyle _demoStyle = TabsDemoStyle.iconsAndText; bool _customIndicator = false; @override void initState() { super.initState(); _controller = TabController(vsync: this, length: _allPages.length); } @override void dispose() { _controller!.dispose(); super.dispose(); } void changeDemoStyle(TabsDemoStyle style) { setState(() { _demoStyle = style; }); } Decoration? getIndicator() { if (!_customIndicator) { return const UnderlineTabIndicator(); } switch (_demoStyle) { case TabsDemoStyle.iconsAndText: return ShapeDecoration( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4.0)), side: BorderSide(color: Colors.white24, width: 2.0), ) + const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4.0)), side: BorderSide(color: Colors.transparent, width: 4.0), ), ); case TabsDemoStyle.iconsOnly: return ShapeDecoration( shape: const CircleBorder(side: BorderSide(color: Colors.white24, width: 4.0)) + const CircleBorder(side: BorderSide(color: Colors.transparent, width: 4.0)), ); case TabsDemoStyle.textOnly: return ShapeDecoration( shape: const StadiumBorder(side: BorderSide(color: Colors.white24, width: 2.0)) + const StadiumBorder(side: BorderSide(color: Colors.transparent, width: 4.0)), ); } } @override Widget build(BuildContext context) { final Color iconColor = Theme.of(context).colorScheme.secondary; return Scaffold( appBar: AppBar( title: const Text('Scrollable tabs'), actions: [ MaterialDemoDocumentationButton(ScrollableTabsDemo.routeName), IconButton( tooltip: 'Custom Indicator', icon: const Icon(Icons.sentiment_very_satisfied), onPressed: () { setState(() { _customIndicator = !_customIndicator; }); }, ), PopupMenuButton( tooltip: 'Popup Menu', onSelected: changeDemoStyle, itemBuilder: (BuildContext context) => >[ const PopupMenuItem( value: TabsDemoStyle.iconsAndText, child: Text('Icons and text'), ), const PopupMenuItem( value: TabsDemoStyle.iconsOnly, child: Text('Icons only'), ), const PopupMenuItem( value: TabsDemoStyle.textOnly, child: Text('Text only'), ), ], ), ], bottom: TabBar( controller: _controller, isScrollable: true, indicator: getIndicator(), tabs: _allPages.map((_Page page) { return switch (_demoStyle) { TabsDemoStyle.iconsAndText => Tab(text: page.text, icon: Icon(page.icon)), TabsDemoStyle.iconsOnly => Tab(icon: Icon(page.icon)), TabsDemoStyle.textOnly => Tab(text: page.text), }; }).toList(), ), ), body: TabBarView( controller: _controller, children: _allPages.map((_Page page) { return SafeArea( top: false, bottom: false, child: Container( key: ObjectKey(page.icon), padding: const EdgeInsets.all(12.0), child: Card( child: Center( child: Icon( page.icon, color: iconColor, size: 128.0, semanticLabel: 'Placeholder for ${page.text} tab', ), ), ), ), ); }).toList(), ), ); } }