Skip to content

Commit 195f606

Browse files
committed
Merged
2 parents fc39e86 + 628e868 commit 195f606

File tree

143 files changed

+4324
-213
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+4324
-213
lines changed

Diff for: 13_bottom_nav_bar/lib/main.dart

+99-46
Original file line numberDiff line numberDiff line change
@@ -6,70 +6,123 @@
66

77
import 'package:flutter/material.dart';
88

9-
void main() => runApp(new MyApp());
9+
void main() => runApp(MyApp());
1010

1111
class MyApp extends StatelessWidget {
1212
@override
1313
Widget build(BuildContext context) {
14-
return new MaterialApp(
15-
title: 'Flutter Bottom Nav Demo',
16-
theme: new ThemeData(
17-
primarySwatch: Colors.deepOrange,
18-
),
19-
// home: new BottomNavigationDemo(),
20-
home: new BottomNavExample()
21-
);
14+
return MaterialApp(
15+
title: 'Flutter Bottom Nav Demo',
16+
theme: ThemeData(
17+
primarySwatch: Colors.deepOrange,
18+
),
19+
home: BottomNavExample());
2220
}
2321
}
2422

2523
class BottomNavExample extends StatefulWidget {
2624
@override
27-
BottomNavExampleState createState() => new BottomNavExampleState();
25+
createState() => BottomNavExampleState();
2826
}
2927

3028
class BottomNavExampleState extends State<BottomNavExample> {
3129
int index = 0;
3230

3331
@override
3432
Widget build(BuildContext context) {
35-
return new Scaffold(
36-
body: new Stack(
37-
children: <Widget>[
38-
// OffStage widgets can be hidden
39-
new Offstage(
40-
offstage: index != 0,
41-
child: new Container(
42-
child: new Center(
43-
child: new Text('Left',
44-
style: Theme.of(context).textTheme.display2)
45-
)
46-
),
47-
),
48-
new Offstage(
49-
offstage: index != 1,
50-
child: new Container(
51-
child: new Center(
52-
child: new Text('Right',
53-
style: Theme.of(context).textTheme.display2)
54-
)
33+
return Scaffold(
34+
body: Body('Index: $index'),
35+
bottomNavigationBar: TwoItemBottomNavBar(
36+
index: index,
37+
callback: (newIndex) => setState(
38+
() => this.index = newIndex,
5539
),
56-
),
57-
],
5840
),
59-
bottomNavigationBar: new BottomNavigationBar(
60-
currentIndex: index,
61-
onTap: (int index) => setState(() => this.index = index),
62-
items: <BottomNavigationBarItem>[
63-
new BottomNavigationBarItem(
64-
icon: new Icon(Icons.home),
65-
title: new Text('Left'),
66-
),
67-
new BottomNavigationBarItem(
68-
icon: new Icon(Icons.search),
69-
title: new Text('Right'),
70-
),
71-
],
41+
);
42+
}
43+
}
44+
45+
class Body extends StatelessWidget {
46+
Body(this.text);
47+
final String text;
48+
@override
49+
Widget build(BuildContext context) {
50+
return Container(
51+
child: Center(
52+
child: Text(
53+
text,
54+
style: Theme.of(context).textTheme.display2,
55+
),
7256
),
7357
);
7458
}
75-
}
59+
}
60+
61+
class TwoItemBottomNavBar extends StatelessWidget {
62+
TwoItemBottomNavBar({this.index, this.callback});
63+
final int index;
64+
final Function(int) callback;
65+
66+
@override
67+
Widget build(BuildContext context) {
68+
/// BottomNavigationBar is automatically set to type 'fixed'
69+
/// when there are three of less items
70+
return BottomNavigationBar(
71+
currentIndex: index,
72+
onTap: callback,
73+
items: <BottomNavigationBarItem>[
74+
BottomNavigationBarItem(
75+
icon: Icon(Icons.home),
76+
title: Text('First'),
77+
),
78+
BottomNavigationBarItem(
79+
icon: Icon(Icons.search),
80+
title: Text('Second'),
81+
),
82+
],
83+
);
84+
}
85+
}
86+
87+
class FiveItemBottomNavBar extends StatelessWidget {
88+
FiveItemBottomNavBar({this.index, this.callback});
89+
final int index;
90+
final Function(int) callback;
91+
92+
@override
93+
Widget build(BuildContext context) {
94+
/// BottomNavigationBar is automatically set to type 'shifting'
95+
/// when there are more than three items. This renders the items in white
96+
return BottomNavigationBar(
97+
currentIndex: index,
98+
onTap: callback,
99+
items: <BottomNavigationBarItem>[
100+
BottomNavigationBarItem(
101+
icon: Icon(Icons.home),
102+
title: Text('First'),
103+
backgroundColor: Colors.teal,
104+
),
105+
BottomNavigationBarItem(
106+
icon: Icon(Icons.search),
107+
title: Text('Second'),
108+
backgroundColor: Colors.pink,
109+
),
110+
BottomNavigationBarItem(
111+
icon: Icon(Icons.search),
112+
title: Text('Third'),
113+
backgroundColor: Colors.amber,
114+
),
115+
BottomNavigationBarItem(
116+
icon: Icon(Icons.search),
117+
title: Text('Fourth'),
118+
backgroundColor: Colors.indigo,
119+
),
120+
BottomNavigationBarItem(
121+
icon: Icon(Icons.search),
122+
title: Text('Fifth'),
123+
backgroundColor: Colors.lime,
124+
)
125+
],
126+
);
127+
}
128+
}

Diff for: 13_bottom_nav_bar/test/widget_test.dart

+9-7
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ import 'package:bottom_nav_bar/main.dart';
66
void main() {
77
testWidgets('Page renders', (WidgetTester tester) async {
88
// Build our app and trigger a frame.
9-
await tester.pumpWidget(new MyApp());
10-
// Verify that 'Left' is rendered twice
11-
expect(find.text('Left'), findsNWidgets(2));
9+
await tester.pumpWidget(MyApp());
10+
// Verify that 'Index: 0' is displayed
11+
expect(find.text('First'), findsNWidgets(1));
12+
expect(find.text('Second'), findsNWidgets(1));
13+
expect(find.text('Index: 0'), findsNWidgets(1));
1214
// Tap the right nav button
1315
await tester.tap(find.byIcon(Icons.search));
1416
await tester.pump();
15-
// Verify that 'Left' is rendered once and Right' twice
16-
expect(find.text('Left'), findsNWidgets(1));
17-
expect(find.text('Right'), findsNWidgets(2));
18-
17+
// Verify that 'Index: 1' is now displayed
18+
expect(find.text('First'), findsNWidgets(1));
19+
expect(find.text('Second'), findsNWidgets(1));
20+
expect(find.text('Index: 1'), findsNWidgets(1));
1921
});
2022
}

Diff for: 16_panels/ios/Runner.xcodeproj/project.pbxproj

+3-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@
9191
9740EEB11CF90186004384FC /* Flutter */,
9292
97C146F01CF9000F007C117D /* Runner */,
9393
97C146EF1CF9000F007C117D /* Products */,
94-
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
9594
);
9695
sourceTree = "<group>";
9796
};
@@ -161,6 +160,7 @@
161160
TargetAttributes = {
162161
97C146ED1CF9000F007C117D = {
163162
CreatedOnToolsVersion = 7.3.1;
163+
DevelopmentTeam = QXW2T6L3C6;
164164
};
165165
};
166166
};
@@ -371,6 +371,7 @@
371371
buildSettings = {
372372
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
373373
CURRENT_PROJECT_VERSION = 1;
374+
DEVELOPMENT_TEAM = QXW2T6L3C6;
374375
ENABLE_BITCODE = NO;
375376
FRAMEWORK_SEARCH_PATHS = (
376377
"$(inherited)",
@@ -394,6 +395,7 @@
394395
buildSettings = {
395396
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
396397
CURRENT_PROJECT_VERSION = 1;
398+
DEVELOPMENT_TEAM = QXW2T6L3C6;
397399
ENABLE_BITCODE = NO;
398400
FRAMEWORK_SEARCH_PATHS = (
399401
"$(inherited)",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>

Diff for: 16_panels/lib/backdrop.dart

+49-56
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,7 @@ class _BackdropPanel extends StatelessWidget {
5050
onVerticalDragUpdate: onVerticalDragUpdate,
5151
onVerticalDragEnd: onVerticalDragEnd,
5252
onTap: onTap,
53-
child: Container(
54-
color: Theme.of(context).primaryColor,
55-
height: titleHeight,
56-
padding: EdgeInsetsDirectional.only(start: 16.0),
57-
alignment: AlignmentDirectional.centerStart,
58-
child: DefaultTextStyle(
59-
style: Theme.of(context).textTheme.subhead,
60-
child: title,
61-
),
62-
),
53+
child: Container(height: titleHeight, child: title),
6354
),
6455
Divider(
6556
height: 1.0,
@@ -81,24 +72,26 @@ class _BackdropPanel extends StatelessWidget {
8172
/// can make a selection. The user can also configure the titles for when the
8273
/// front or back panel is showing.
8374
class Backdrop extends StatefulWidget {
84-
final Widget frontPanel;
85-
final Widget backPanel;
75+
final Widget frontLayer;
76+
final Widget backLayer;
8677
final Widget frontHeader;
87-
final double backPanelHeight;
88-
final double frontPanelClosedHeight;
78+
final double frontPanelOpenHeight;
79+
final double frontHeaderHeight;
80+
final bool frontHeaderVisibleClosed;
8981
final EdgeInsets frontPanelPadding;
9082
final ValueNotifier<bool> panelVisible;
9183

9284
Backdrop(
93-
{@required this.frontPanel,
94-
@required this.backPanel,
95-
this.backPanelHeight = 0.0,
96-
this.frontPanelClosedHeight = 48.0,
85+
{@required this.frontLayer,
86+
@required this.backLayer,
87+
this.frontPanelOpenHeight = 0.0,
88+
this.frontHeaderHeight = 48.0,
9789
this.frontPanelPadding = const EdgeInsets.all(0.0),
90+
this.frontHeaderVisibleClosed = true,
9891
this.panelVisible,
9992
this.frontHeader})
100-
: assert(frontPanel != null),
101-
assert(backPanel != null);
93+
: assert(frontLayer != null),
94+
assert(backLayer != null);
10295

10396
@override
10497
createState() => _BackdropState();
@@ -143,8 +136,8 @@ class _BackdropState extends State<Backdrop>
143136
@override
144137
void didUpdateWidget(Backdrop oldWidget) {
145138
super.didUpdateWidget(oldWidget);
146-
oldWidget.panelVisible.removeListener(_subscribeToValueNotifier);
147-
widget.panelVisible.addListener(_subscribeToValueNotifier);
139+
oldWidget.panelVisible?.removeListener(_subscribeToValueNotifier);
140+
widget.panelVisible?.addListener(_subscribeToValueNotifier);
148141
}
149142

150143
@override
@@ -188,39 +181,39 @@ class _BackdropState extends State<Backdrop>
188181
}
189182

190183
@override
191-
Widget build(BuildContext context) => LayoutBuilder(
192-
builder: (BuildContext context, BoxConstraints constraints) {
193-
final panelTitleHeight = widget.frontPanelClosedHeight;
194-
final panelSize = constraints.biggest;
195-
final panelTop = panelSize.height - panelTitleHeight;
196-
// final panelTop = panelSize.height;
197-
198-
// Animate the front panel sliding up and down
199-
Animation<RelativeRect> panelAnimation = RelativeRectTween(
200-
begin: RelativeRect.fromLTRB(
201-
0.0, panelTop, 0.0, panelTop - panelSize.height),
202-
end: RelativeRect.fromLTRB(0.0, widget.backPanelHeight, 0.0, 0.0),
203-
).animate(_controller.view);
204-
205-
return Container(
206-
key: _backdropKey,
207-
child: Stack(
208-
children: <Widget>[
209-
widget.backPanel,
210-
PositionedTransition(
211-
rect: panelAnimation,
212-
child: _BackdropPanel(
213-
onTap: _toggleBackdropPanelVisibility,
214-
onVerticalDragUpdate: _handleDragUpdate,
215-
onVerticalDragEnd: _handleDragEnd,
216-
title: widget.frontHeader,
217-
titleHeight: panelTitleHeight,
218-
child: widget.frontPanel,
219-
padding: widget.frontPanelPadding,
220-
),
184+
Widget build(BuildContext context) {
185+
return LayoutBuilder(builder: (context, constraints) {
186+
final panelSize = constraints.biggest;
187+
final closedPercentage = widget.frontHeaderVisibleClosed
188+
? (panelSize.height - widget.frontHeaderHeight) / panelSize.height
189+
: 1.0;
190+
final openPercentage = widget.frontPanelOpenHeight / panelSize.height;
191+
192+
final panelDetailsPosition = Tween<Offset>(
193+
begin: Offset(0.0, closedPercentage),
194+
end: Offset(0.0, openPercentage),
195+
).animate(_controller.view);
196+
197+
return Container(
198+
key: _backdropKey,
199+
child: Stack(
200+
children: <Widget>[
201+
widget.backLayer,
202+
SlideTransition(
203+
position: panelDetailsPosition,
204+
child: _BackdropPanel(
205+
onTap: _toggleBackdropPanelVisibility,
206+
onVerticalDragUpdate: _handleDragUpdate,
207+
onVerticalDragEnd: _handleDragEnd,
208+
title: widget.frontHeader,
209+
titleHeight: widget.frontHeaderHeight,
210+
child: widget.frontLayer,
211+
padding: widget.frontPanelPadding,
221212
),
222-
],
223-
),
224-
);
225-
});
213+
),
214+
],
215+
),
216+
);
217+
});
218+
}
226219
}

0 commit comments

Comments
 (0)