1// Copyright 2015 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import 'package:flutter/material.dart'; 6 7import '../../gallery/demo.dart'; 8 9enum TabsDemoStyle { 10 iconsAndText, 11 iconsOnly, 12 textOnly 13} 14 15class _Page { 16 const _Page({ this.icon, this.text }); 17 final IconData icon; 18 final String text; 19} 20 21const List<_Page> _allPages = <_Page>[ 22 _Page(icon: Icons.grade, text: 'TRIUMPH'), 23 _Page(icon: Icons.playlist_add, text: 'NOTE'), 24 _Page(icon: Icons.check_circle, text: 'SUCCESS'), 25 _Page(icon: Icons.question_answer, text: 'OVERSTATE'), 26 _Page(icon: Icons.sentiment_very_satisfied, text: 'SATISFACTION'), 27 _Page(icon: Icons.camera, text: 'APERTURE'), 28 _Page(icon: Icons.assignment_late, text: 'WE MUST'), 29 _Page(icon: Icons.assignment_turned_in, text: 'WE CAN'), 30 _Page(icon: Icons.group, text: 'ALL'), 31 _Page(icon: Icons.block, text: 'EXCEPT'), 32 _Page(icon: Icons.sentiment_very_dissatisfied, text: 'CRYING'), 33 _Page(icon: Icons.error, text: 'MISTAKE'), 34 _Page(icon: Icons.loop, text: 'TRYING'), 35 _Page(icon: Icons.cake, text: 'CAKE'), 36]; 37 38class ScrollableTabsDemo extends StatefulWidget { 39 static const String routeName = '/material/scrollable-tabs'; 40 41 @override 42 ScrollableTabsDemoState createState() => ScrollableTabsDemoState(); 43} 44 45class ScrollableTabsDemoState extends State<ScrollableTabsDemo> with SingleTickerProviderStateMixin { 46 TabController _controller; 47 TabsDemoStyle _demoStyle = TabsDemoStyle.iconsAndText; 48 bool _customIndicator = false; 49 50 @override 51 void initState() { 52 super.initState(); 53 _controller = TabController(vsync: this, length: _allPages.length); 54 } 55 56 @override 57 void dispose() { 58 _controller.dispose(); 59 super.dispose(); 60 } 61 62 void changeDemoStyle(TabsDemoStyle style) { 63 setState(() { 64 _demoStyle = style; 65 }); 66 } 67 68 Decoration getIndicator() { 69 if (!_customIndicator) 70 return const UnderlineTabIndicator(); 71 72 switch(_demoStyle) { 73 case TabsDemoStyle.iconsAndText: 74 return ShapeDecoration( 75 shape: const RoundedRectangleBorder( 76 borderRadius: BorderRadius.all(Radius.circular(4.0)), 77 side: BorderSide( 78 color: Colors.white24, 79 width: 2.0, 80 ), 81 ) + const RoundedRectangleBorder( 82 borderRadius: BorderRadius.all(Radius.circular(4.0)), 83 side: BorderSide( 84 color: Colors.transparent, 85 width: 4.0, 86 ), 87 ), 88 ); 89 90 case TabsDemoStyle.iconsOnly: 91 return ShapeDecoration( 92 shape: const CircleBorder( 93 side: BorderSide( 94 color: Colors.white24, 95 width: 4.0, 96 ), 97 ) + const CircleBorder( 98 side: BorderSide( 99 color: Colors.transparent, 100 width: 4.0, 101 ), 102 ), 103 ); 104 105 case TabsDemoStyle.textOnly: 106 return ShapeDecoration( 107 shape: const StadiumBorder( 108 side: BorderSide( 109 color: Colors.white24, 110 width: 2.0, 111 ), 112 ) + const StadiumBorder( 113 side: BorderSide( 114 color: Colors.transparent, 115 width: 4.0, 116 ), 117 ), 118 ); 119 } 120 return null; 121 } 122 123 @override 124 Widget build(BuildContext context) { 125 final Color iconColor = Theme.of(context).accentColor; 126 return Scaffold( 127 appBar: AppBar( 128 title: const Text('Scrollable tabs'), 129 actions: <Widget>[ 130 MaterialDemoDocumentationButton(ScrollableTabsDemo.routeName), 131 IconButton( 132 icon: const Icon(Icons.sentiment_very_satisfied), 133 onPressed: () { 134 setState(() { 135 _customIndicator = !_customIndicator; 136 }); 137 }, 138 ), 139 PopupMenuButton<TabsDemoStyle>( 140 onSelected: changeDemoStyle, 141 itemBuilder: (BuildContext context) => <PopupMenuItem<TabsDemoStyle>>[ 142 const PopupMenuItem<TabsDemoStyle>( 143 value: TabsDemoStyle.iconsAndText, 144 child: Text('Icons and text'), 145 ), 146 const PopupMenuItem<TabsDemoStyle>( 147 value: TabsDemoStyle.iconsOnly, 148 child: Text('Icons only'), 149 ), 150 const PopupMenuItem<TabsDemoStyle>( 151 value: TabsDemoStyle.textOnly, 152 child: Text('Text only'), 153 ), 154 ], 155 ), 156 ], 157 bottom: TabBar( 158 controller: _controller, 159 isScrollable: true, 160 indicator: getIndicator(), 161 tabs: _allPages.map<Tab>((_Page page) { 162 assert(_demoStyle != null); 163 switch (_demoStyle) { 164 case TabsDemoStyle.iconsAndText: 165 return Tab(text: page.text, icon: Icon(page.icon)); 166 case TabsDemoStyle.iconsOnly: 167 return Tab(icon: Icon(page.icon)); 168 case TabsDemoStyle.textOnly: 169 return Tab(text: page.text); 170 } 171 return null; 172 }).toList(), 173 ), 174 ), 175 body: TabBarView( 176 controller: _controller, 177 children: _allPages.map<Widget>((_Page page) { 178 return SafeArea( 179 top: false, 180 bottom: false, 181 child: Container( 182 key: ObjectKey(page.icon), 183 padding: const EdgeInsets.all(12.0), 184 child: Card( 185 child: Center( 186 child: Icon( 187 page.icon, 188 color: iconColor, 189 size: 128.0, 190 semanticLabel: 'Placeholder for ${page.text} tab', 191 ), 192 ), 193 ), 194 ), 195 ); 196 }).toList(), 197 ), 198 ); 199 } 200} 201