1 | // Copyright 2014 The Flutter 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 | |
5 | import 'package:flutter/material.dart'; |
6 | import '../../gallery_localizations.dart'; |
7 | import 'material_demo_types.dart'; |
8 | |
9 | class TabsDemo extends StatelessWidget { |
10 | const TabsDemo({super.key, required this.type}); |
11 | |
12 | final TabsDemoType type; |
13 | |
14 | @override |
15 | Widget build(BuildContext context) { |
16 | return switch (type) { |
17 | TabsDemoType.scrollable => _TabsScrollableDemo(), |
18 | TabsDemoType.nonScrollable => _TabsNonScrollableDemo(), |
19 | }; |
20 | } |
21 | } |
22 | |
23 | // BEGIN tabsScrollableDemo |
24 | |
25 | class _TabsScrollableDemo extends StatefulWidget { |
26 | @override |
27 | __TabsScrollableDemoState createState() => __TabsScrollableDemoState(); |
28 | } |
29 | |
30 | class __TabsScrollableDemoState extends State<_TabsScrollableDemo> |
31 | with SingleTickerProviderStateMixin, RestorationMixin { |
32 | TabController? _tabController; |
33 | |
34 | final RestorableInt tabIndex = RestorableInt(0); |
35 | |
36 | @override |
37 | String get restorationId => 'tab_scrollable_demo' ; |
38 | |
39 | @override |
40 | void restoreState(RestorationBucket? oldBucket, bool initialRestore) { |
41 | registerForRestoration(tabIndex, 'tab_index' ); |
42 | _tabController!.index = tabIndex.value; |
43 | } |
44 | |
45 | @override |
46 | void initState() { |
47 | _tabController = TabController(length: 12, vsync: this); |
48 | _tabController!.addListener(() { |
49 | // When the tab controller's value is updated, make sure to update the |
50 | // tab index value, which is state restorable. |
51 | setState(() { |
52 | tabIndex.value = _tabController!.index; |
53 | }); |
54 | }); |
55 | super.initState(); |
56 | } |
57 | |
58 | @override |
59 | void dispose() { |
60 | _tabController!.dispose(); |
61 | tabIndex.dispose(); |
62 | super.dispose(); |
63 | } |
64 | |
65 | @override |
66 | Widget build(BuildContext context) { |
67 | final GalleryLocalizations localizations = GalleryLocalizations.of(context)!; |
68 | final List<String> tabs = <String>[ |
69 | localizations.colorsRed, |
70 | localizations.colorsOrange, |
71 | localizations.colorsGreen, |
72 | localizations.colorsBlue, |
73 | localizations.colorsIndigo, |
74 | localizations.colorsPurple, |
75 | localizations.colorsRed, |
76 | localizations.colorsOrange, |
77 | localizations.colorsGreen, |
78 | localizations.colorsBlue, |
79 | localizations.colorsIndigo, |
80 | localizations.colorsPurple, |
81 | ]; |
82 | |
83 | return Scaffold( |
84 | appBar: AppBar( |
85 | automaticallyImplyLeading: false, |
86 | title: Text(localizations.demoTabsScrollingTitle), |
87 | bottom: TabBar( |
88 | controller: _tabController, |
89 | isScrollable: true, |
90 | tabs: <Widget>[for (final String tab in tabs) Tab(text: tab)], |
91 | ), |
92 | ), |
93 | body: TabBarView( |
94 | controller: _tabController, |
95 | children: <Widget>[for (final String tab in tabs) Center(child: Text(tab))], |
96 | ), |
97 | ); |
98 | } |
99 | } |
100 | |
101 | // END |
102 | |
103 | // BEGIN tabsNonScrollableDemo |
104 | |
105 | class _TabsNonScrollableDemo extends StatefulWidget { |
106 | @override |
107 | __TabsNonScrollableDemoState createState() => __TabsNonScrollableDemoState(); |
108 | } |
109 | |
110 | class __TabsNonScrollableDemoState extends State<_TabsNonScrollableDemo> |
111 | with SingleTickerProviderStateMixin, RestorationMixin { |
112 | late TabController _tabController; |
113 | |
114 | final RestorableInt tabIndex = RestorableInt(0); |
115 | |
116 | @override |
117 | String get restorationId => 'tab_non_scrollable_demo' ; |
118 | |
119 | @override |
120 | void restoreState(RestorationBucket? oldBucket, bool initialRestore) { |
121 | registerForRestoration(tabIndex, 'tab_index' ); |
122 | _tabController.index = tabIndex.value; |
123 | } |
124 | |
125 | @override |
126 | void initState() { |
127 | super.initState(); |
128 | _tabController = TabController(length: 3, vsync: this); |
129 | _tabController.addListener(() { |
130 | // When the tab controller's value is updated, make sure to update the |
131 | // tab index value, which is state restorable. |
132 | setState(() { |
133 | tabIndex.value = _tabController.index; |
134 | }); |
135 | }); |
136 | } |
137 | |
138 | @override |
139 | void dispose() { |
140 | _tabController.dispose(); |
141 | tabIndex.dispose(); |
142 | super.dispose(); |
143 | } |
144 | |
145 | @override |
146 | Widget build(BuildContext context) { |
147 | final GalleryLocalizations localizations = GalleryLocalizations.of(context)!; |
148 | final List<String> tabs = <String>[ |
149 | localizations.colorsRed, |
150 | localizations.colorsOrange, |
151 | localizations.colorsGreen, |
152 | ]; |
153 | |
154 | return Scaffold( |
155 | appBar: AppBar( |
156 | automaticallyImplyLeading: false, |
157 | title: Text(localizations.demoTabsNonScrollingTitle), |
158 | bottom: TabBar( |
159 | controller: _tabController, |
160 | tabs: <Widget>[for (final String tab in tabs) Tab(text: tab)], |
161 | ), |
162 | ), |
163 | body: TabBarView( |
164 | controller: _tabController, |
165 | children: <Widget>[for (final String tab in tabs) Center(child: Text(tab))], |
166 | ), |
167 | ); |
168 | } |
169 | } |
170 | |
171 | // END |
172 | |