// 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'; const String _explanatoryText = "When the Scaffold's floating action button changes, the new button fades and " 'turns into view. In this demo, changing tabs can cause the app to be rebuilt ' 'with a FloatingActionButton that the Scaffold distinguishes from the others ' 'by its key.'; class _Page { _Page({this.label, this.colors, this.icon}); final String? label; final MaterialColor? colors; final IconData? icon; Color get labelColor => colors != null ? colors!.shade300 : Colors.grey.shade300; bool get fabDefined => colors != null && icon != null; Color get fabColor => colors!.shade400; Icon get fabIcon => Icon(icon); Key get fabKey => ValueKey(fabColor); } final List<_Page> _allPages = <_Page>[ _Page(label: 'Pink', colors: Colors.pink, icon: Icons.add), _Page(label: 'Eco', colors: Colors.green, icon: Icons.create), _Page(label: 'No'), _Page(label: 'Teal', colors: Colors.teal, icon: Icons.add), _Page(label: 'Red', colors: Colors.red, icon: Icons.create), ]; class TabsFabDemo extends StatefulWidget { const TabsFabDemo({super.key}); static const String routeName = '/material/tabs-fab'; @override State createState() => _TabsFabDemoState(); } class _TabsFabDemoState extends State with SingleTickerProviderStateMixin { final GlobalKey _scaffoldKey = GlobalKey(); TabController? _controller; late _Page _selectedPage; bool _extendedButtons = false; @override void initState() { super.initState(); _controller = TabController(vsync: this, length: _allPages.length); _controller!.addListener(_handleTabSelection); _selectedPage = _allPages[0]; } @override void dispose() { _controller!.dispose(); super.dispose(); } void _handleTabSelection() { setState(() { _selectedPage = _allPages[_controller!.index]; }); } void _showExplanatoryText() { _scaffoldKey.currentState!.showBottomSheet((BuildContext context) { return Container( decoration: BoxDecoration( border: Border(top: BorderSide(color: Theme.of(context).dividerColor)), ), child: Padding( padding: const EdgeInsets.all(32.0), child: Text(_explanatoryText, style: Theme.of(context).textTheme.titleMedium), ), ); }); } Widget buildTabView(_Page page) { return Builder( builder: (BuildContext context) { return Container( key: ValueKey(page.label), padding: const EdgeInsets.fromLTRB(48.0, 48.0, 48.0, 96.0), child: Card( child: Center( child: Text( page.label!, style: TextStyle(color: page.labelColor, fontSize: 32.0), textAlign: TextAlign.center, ), ), ), ); }, ); } Widget? buildFloatingActionButton(_Page page) { if (!page.fabDefined) { return null; } if (_extendedButtons) { return FloatingActionButton.extended( key: ValueKey(page.fabKey), tooltip: 'Show explanation', backgroundColor: page.fabColor, icon: page.fabIcon, label: Text(page.label!.toUpperCase()), onPressed: _showExplanatoryText, ); } return FloatingActionButton( key: page.fabKey, tooltip: 'Show explanation', backgroundColor: page.fabColor, onPressed: _showExplanatoryText, child: page.fabIcon, ); } @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, appBar: AppBar( title: const Text('FAB per tab'), bottom: TabBar( controller: _controller, tabs: _allPages .map((_Page page) => Tab(text: page.label!.toUpperCase())) .toList(), ), actions: [ MaterialDemoDocumentationButton(TabsFabDemo.routeName), IconButton( icon: const Icon( Icons.sentiment_very_satisfied, semanticLabel: 'Toggle extended buttons', ), onPressed: () { setState(() { _extendedButtons = !_extendedButtons; }); }, ), ], ), floatingActionButton: buildFloatingActionButton(_selectedPage), body: TabBarView( controller: _controller, children: _allPages.map(buildTabView).toList(), ), ); } }