Line data Source code
1 : import 'package:flutter/material.dart';
2 :
3 : import '../navigation_controller.dart';
4 : import 'index.dart';
5 :
6 : /// A [NavigatorBuilder] that allows to switch between destinations using
7 : /// [BottomNavigationBar].
8 : ///
9 : /// It builds a wrapper widget, which is a [Scaffold] with a [Scaffold.body] set
10 : /// to the current destination's content, and [Scaffold.bottomNavigationBar]
11 : /// specified.
12 : ///
13 : /// The [bottomNavigationItems] must correspond to the navigator's destinations.
14 : ///
15 : /// The bottom navigation bar can be customized using [parameters], which includes
16 : /// all parameters supported by the [BottomNavigationBar] widget.
17 : ///
18 : /// See also:
19 : /// - [NavigatorBuilder]
20 : /// - [BottomNavigationBarParameters]
21 : /// - [NavigationController]
22 : /// - [BottomNavigationBar]
23 : ///
24 : class BottomNavigationBuilder implements NavigatorBuilder {
25 : /// Creates a [BottomNavigationBuilder] instance.
26 : ///
27 0 : const BottomNavigationBuilder({
28 : required this.bottomNavigationItems,
29 : this.parameters = const BottomNavigationBarParameters(),
30 : });
31 :
32 : /// A list of [BottomNavigationBarItems], that corresponds to the navigator's
33 : /// destination list.
34 : ///
35 : /// The list must contain the same number of bottom navigation bar items,
36 : /// following with the same order as a destination list specified for the navigator.
37 : ///
38 : final List<BottomNavigationBarItem> bottomNavigationItems;
39 :
40 : /// A set of [BottomNavigationBar] parameters.
41 : ///
42 : /// Contains all supported parameters to customize [BottomNavigationBar] widget.
43 : /// Doesn't include 'items', 'onTap' and 'currentIndex', which are managed by
44 : /// [BottomNavigationBuilder].
45 : ///
46 : final BottomNavigationBarParameters parameters;
47 :
48 0 : @override
49 : Widget build(BuildContext context, NavigationController navigator) {
50 0 : final currentDestination = navigator.currentDestination;
51 0 : final content = currentDestination.build(context);
52 0 : return _BottomNavigationWrapper(
53 : content: content,
54 0 : items: bottomNavigationItems,
55 0 : parameters: parameters,
56 0 : onSelectBottomTab: (index) =>
57 0 : navigator.goTo(navigator.destinations[index]),
58 0 : selectedIndex: navigator.destinations.indexOf(currentDestination),
59 : );
60 : }
61 : }
62 :
63 : class _BottomNavigationWrapper extends StatefulWidget {
64 0 : const _BottomNavigationWrapper({
65 : Key? key,
66 : required this.content,
67 : required this.items,
68 : required this.onSelectBottomTab,
69 : required this.selectedIndex,
70 : required this.parameters,
71 0 : }) : super(key: key);
72 :
73 : final Widget content;
74 :
75 : final List<BottomNavigationBarItem> items;
76 :
77 : final void Function(int) onSelectBottomTab;
78 :
79 : final int selectedIndex;
80 :
81 : final BottomNavigationBarParameters parameters;
82 :
83 0 : @override
84 : _BottomNavigationWrapperState createState() =>
85 0 : _BottomNavigationWrapperState();
86 : }
87 :
88 : class _BottomNavigationWrapperState extends State<_BottomNavigationWrapper> {
89 : late final OverlayEntry _mainOverlay;
90 :
91 0 : @override
92 : void initState() {
93 0 : super.initState();
94 0 : _mainOverlay = OverlayEntry(
95 0 : builder: (context) => Scaffold(
96 0 : body: widget.content,
97 0 : bottomNavigationBar: BottomNavigationBar(
98 0 : items: widget.items,
99 0 : currentIndex: widget.selectedIndex,
100 0 : onTap: widget.onSelectBottomTab,
101 0 : elevation: widget.parameters.elevation,
102 0 : type: widget.parameters.type,
103 0 : fixedColor: widget.parameters.fixedColor,
104 0 : backgroundColor: widget.parameters.backgroundColor,
105 0 : iconSize: widget.parameters.iconSize,
106 0 : selectedItemColor: widget.parameters.selectedItemColor,
107 0 : unselectedItemColor: widget.parameters.unselectedItemColor,
108 0 : selectedIconTheme: widget.parameters.selectedIconTheme,
109 0 : unselectedIconTheme: widget.parameters.unselectedIconTheme,
110 0 : selectedFontSize: widget.parameters.selectedFontSize,
111 0 : unselectedFontSize: widget.parameters.unselectedFontSize,
112 0 : selectedLabelStyle: widget.parameters.selectedLabelStyle,
113 0 : unselectedLabelStyle: widget.parameters.unselectedLabelStyle,
114 0 : showSelectedLabels: widget.parameters.showSelectedLabels,
115 0 : showUnselectedLabels: widget.parameters.showUnselectedLabels,
116 0 : mouseCursor: widget.parameters.mouseCursor,
117 0 : enableFeedback: widget.parameters.enableFeedback,
118 0 : landscapeLayout: widget.parameters.landscapeLayout,
119 : ),
120 : ),
121 : );
122 : }
123 :
124 0 : @override
125 : void didUpdateWidget(_BottomNavigationWrapper oldWidget) {
126 0 : super.didUpdateWidget(oldWidget);
127 0 : if (oldWidget.selectedIndex != widget.selectedIndex) {
128 0 : _mainOverlay.markNeedsBuild();
129 : }
130 : }
131 :
132 0 : @override
133 : Widget build(BuildContext context) {
134 0 : return Overlay(
135 0 : initialEntries: [
136 0 : _mainOverlay,
137 : ],
138 : );
139 : }
140 : }
141 :
142 : /// Contains parameters to customize the [BottomNavigationBar].
143 : ///
144 : /// It includes all the same arguments as the [BottomNavigationBar()], excepting
145 : /// the 'items', 'onTap' and 'currentIndex', which are managed by the [BottomNavigationBuilder].
146 : ///
147 : /// See also:
148 : /// - [BottomNavigationBuilder]
149 : /// - [BottomNavigationBar]
150 : ///
151 : class BottomNavigationBarParameters {
152 : /// Create a [BottomNavigationBarParameters] instance.
153 : ///
154 9 : const BottomNavigationBarParameters({
155 : this.elevation,
156 : this.type,
157 : this.fixedColor,
158 : this.backgroundColor,
159 : this.iconSize = 24.0,
160 : this.selectedItemColor,
161 : this.unselectedItemColor,
162 : this.selectedIconTheme,
163 : this.unselectedIconTheme,
164 : this.selectedFontSize = 14.0,
165 : this.unselectedFontSize = 12.0,
166 : this.selectedLabelStyle,
167 : this.unselectedLabelStyle,
168 : this.showSelectedLabels,
169 : this.showUnselectedLabels,
170 : this.mouseCursor,
171 : this.enableFeedback,
172 : this.landscapeLayout,
173 : });
174 :
175 : /// [BottomNavigationBar.elevation]
176 : ///
177 : final double? elevation;
178 :
179 : /// [BottomNavigationBar.type]
180 : ///
181 : final BottomNavigationBarType? type;
182 :
183 : /// [BottomNavigationBar.fixedColor]
184 : ///
185 : final Color? fixedColor;
186 :
187 : /// [BottomNavigationBar.backgroundColor]
188 : ///
189 : final Color? backgroundColor;
190 :
191 : /// [BottomNavigationBar.iconSize]
192 : ///
193 : final double iconSize;
194 :
195 : /// [BottomNavigationBar.selectedItemColor]
196 : ///
197 : final Color? selectedItemColor;
198 :
199 : /// [BottomNavigationBar.unselectedItemColor]
200 : ///
201 : final Color? unselectedItemColor;
202 :
203 : /// [BottomNavigationBar.selectedIconTheme]
204 : ///
205 : final IconThemeData? selectedIconTheme;
206 :
207 : /// [BottomNavigationBar.unselectedIconTheme]
208 : ///
209 : final IconThemeData? unselectedIconTheme;
210 :
211 : /// [BottomNavigationBar.selectedLabelStyle]
212 : ///
213 : final TextStyle? selectedLabelStyle;
214 :
215 : /// [BottomNavigationBar.unselectedLabelStyle]
216 : ///
217 : final TextStyle? unselectedLabelStyle;
218 :
219 : /// [BottomNavigationBar.selectedFontSize]
220 : ///
221 : final double selectedFontSize;
222 :
223 : /// [BottomNavigationBar.unselectedFontSize]
224 : ///
225 : final double unselectedFontSize;
226 :
227 : /// [BottomNavigationBar.showUnselectedLabels]
228 : ///
229 : final bool? showUnselectedLabels;
230 :
231 : /// [BottomNavigationBar.showSelectedLabels]
232 : ///
233 : final bool? showSelectedLabels;
234 :
235 : /// [BottomNavigationBar.mouseCursor]
236 : ///
237 : final MouseCursor? mouseCursor;
238 :
239 : /// [BottomNavigationBar.enableFeedback]
240 : ///
241 : final bool? enableFeedback;
242 :
243 : /// [BottomNavigationBar.landscapeLayout]
244 : ///
245 : final BottomNavigationBarLandscapeLayout? landscapeLayout;
246 : }
|