Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
7456f6ae
Commit
7456f6ae
authored
Mar 21, 2016
by
Hans Muller
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2782 from HansMuller/app_bar
Flexible AppBar with a TabBar
parents
dab672d1
070fdf77
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
339 additions
and
159 deletions
+339
-159
flexible_space_demo.dart
examples/material_gallery/lib/demo/flexible_space_demo.dart
+3
-2
scrollable_tabs_demo.dart
examples/material_gallery/lib/demo/scrollable_tabs_demo.dart
+109
-0
tabs_demo.dart
examples/material_gallery/lib/demo/tabs_demo.dart
+60
-41
tabs_fab_demo.dart
examples/material_gallery/lib/demo/tabs_fab_demo.dart
+0
-1
home.dart
examples/material_gallery/lib/gallery/home.dart
+6
-3
section.dart
examples/material_gallery/lib/gallery/section.dart
+3
-2
app_bar.dart
packages/flutter/lib/src/material/app_bar.dart
+102
-54
constants.dart
packages/flutter/lib/src/material/constants.dart
+2
-2
flexible_space_bar.dart
packages/flutter/lib/src/material/flexible_space_bar.dart
+8
-5
scaffold.dart
packages/flutter/lib/src/material/scaffold.dart
+36
-47
tabs.dart
packages/flutter/lib/src/material/tabs.dart
+10
-2
No files found.
examples/material_gallery/lib/demo/flexible_space_demo.dart
View file @
7456f6ae
...
...
@@ -82,6 +82,7 @@ class FlexibleSpaceDemoState extends State<FlexibleSpaceDemo> {
@override
Widget
build
(
BuildContext
context
)
{
final
double
statusBarHeight
=
(
MediaQuery
.
of
(
context
)?.
padding
??
EdgeInsets
.
zero
).
top
;
return
new
Theme
(
data:
new
ThemeData
(
brightness:
ThemeBrightness
.
light
,
...
...
@@ -89,10 +90,10 @@ class FlexibleSpaceDemoState extends State<FlexibleSpaceDemo> {
),
child:
new
Scaffold
(
key:
scaffoldKey
,
appBarHeight:
appBarHeight
,
scrollableKey:
scrollableKey
,
appBarBehavior:
_appBarBehavior
,
appBar:
new
AppBar
(
expandedHeight:
appBarHeight
,
actions:
<
Widget
>[
new
IconButton
(
icon:
Icons
.
create
,
...
...
@@ -134,7 +135,7 @@ class FlexibleSpaceDemoState extends State<FlexibleSpaceDemo> {
),
body:
new
Block
(
scrollableKey:
scrollableKey
,
padding:
new
EdgeInsets
.
only
(
top:
appBarHeight
),
padding:
new
EdgeInsets
.
only
(
top:
appBarHeight
+
statusBarHeight
),
children:
<
Widget
>[
new
_ContactCategory
(
icon:
Icons
.
call
,
...
...
examples/material_gallery/lib/demo/scrollable_tabs_demo.dart
0 → 100644
View file @
7456f6ae
// Copyright 2015 The Chromium 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'
;
enum
TabsDemoStyle
{
iconsAndText
,
iconsOnly
,
textOnly
}
class
ScrollableTabsDemo
extends
StatefulWidget
{
@override
ScrollableTabsDemoState
createState
()
=>
new
ScrollableTabsDemoState
();
}
class
ScrollableTabsDemoState
extends
State
<
ScrollableTabsDemo
>
{
final
List
<
IconData
>
icons
=
<
IconData
>[
Icons
.
event
,
Icons
.
home
,
Icons
.
android
,
Icons
.
alarm
,
Icons
.
face
,
Icons
.
language
,
];
final
Map
<
IconData
,
String
>
labels
=
<
IconData
,
String
>{
Icons
.
event
:
'EVENT'
,
Icons
.
home
:
'HOME'
,
Icons
.
android
:
'ANDROID'
,
Icons
.
alarm
:
'ALARM'
,
Icons
.
face
:
'FACE'
,
Icons
.
language
:
'LANGUAGE'
,
};
TabsDemoStyle
_demoStyle
=
TabsDemoStyle
.
iconsAndText
;
void
changeDemoStyle
(
TabsDemoStyle
style
)
{
setState
(()
{
_demoStyle
=
style
;
});
}
@override
Widget
build
(
BuildContext
context
)
{
final
Color
iconColor
=
Theme
.
of
(
context
).
accentColor
;
return
new
TabBarSelection
<
IconData
>(
values:
icons
,
child:
new
Scaffold
(
appBar:
new
AppBar
(
title:
new
Text
(
'Scrollable Tabs'
),
actions:
<
Widget
>[
new
PopupMenuButton
<
TabsDemoStyle
>(
onSelected:
changeDemoStyle
,
items:
<
PopupMenuItem
<
TabsDemoStyle
>>[
new
PopupMenuItem
<
TabsDemoStyle
>(
value:
TabsDemoStyle
.
iconsAndText
,
child:
new
Text
(
'Icons and Text'
)
),
new
PopupMenuItem
<
TabsDemoStyle
>(
value:
TabsDemoStyle
.
iconsOnly
,
child:
new
Text
(
'Icons Only'
)
),
new
PopupMenuItem
<
TabsDemoStyle
>(
value:
TabsDemoStyle
.
textOnly
,
child:
new
Text
(
'Text Only'
)
),
]
)
],
tabBar:
new
TabBar
<
IconData
>(
isScrollable:
true
,
labels:
new
Map
<
IconData
,
TabLabel
>.
fromIterable
(
icons
,
value:
(
IconData
icon
)
{
switch
(
_demoStyle
)
{
case
TabsDemoStyle
.
iconsAndText
:
return
new
TabLabel
(
text:
labels
[
icon
],
icon:
icon
);
case
TabsDemoStyle
.
iconsOnly
:
return
new
TabLabel
(
icon:
icon
);
case
TabsDemoStyle
.
textOnly
:
return
new
TabLabel
(
text:
labels
[
icon
]);
}
}
)
)
),
body:
new
TabBarView
<
IconData
>(
children:
icons
.
map
((
IconData
icon
)
{
return
new
Container
(
key:
new
ObjectKey
(
icon
),
padding:
const
EdgeInsets
.
all
(
12.0
),
child:
new
Card
(
child:
new
Center
(
child:
new
Icon
(
icon:
icon
,
color:
iconColor
,
size:
128.0
)
)
)
);
}).
toList
()
)
)
);
}
}
examples/material_gallery/lib/demo/tabs_demo.dart
View file @
7456f6ae
...
...
@@ -4,55 +4,74 @@
import
'package:flutter/material.dart'
;
class
TabsDemo
extends
StatelessWidget
{
final
List
<
IconData
>
icons
=
<
IconData
>[
Icons
.
event
,
Icons
.
home
,
Icons
.
android
,
Icons
.
alarm
,
Icons
.
face
,
Icons
.
language
,
];
final
Map
<
IconData
,
String
>
labels
=
<
IconData
,
String
>{
Icons
.
event
:
'EVENT'
,
Icons
.
home
:
'HOME'
,
Icons
.
android
:
'ANDROID'
,
Icons
.
alarm
:
'ALARM'
,
Icons
.
face
:
'FACE'
,
Icons
.
language
:
'LANGUAGE'
,
};
class
_Page
{
_Page
({
this
.
label
});
final
GlobalKey
<
ScrollableState
<
Scrollable
>>
key
=
new
GlobalKey
<
ScrollableState
<
Scrollable
>>();
final
String
label
;
}
final
List
<
_Page
>
_pages
=
<
_Page
>[
new
_Page
(
label:
'ONE'
),
new
_Page
(
label:
'TWO'
),
new
_Page
(
label:
'FREE'
),
new
_Page
(
label:
'FOUR'
)
];
class
TabsDemo
extends
StatefulWidget
{
@override
TabsDemoState
createState
()
=>
new
TabsDemoState
();
}
class
TabsDemoState
extends
State
<
TabsDemo
>
{
_Page
_selectedPage
;
double
_scrollOffset
=
0.0
;
@override
void
initState
()
{
super
.
initState
();
_selectedPage
=
_pages
[
0
];
}
@override
Widget
build
(
BuildContext
context
)
{
final
Color
iconColor
=
Theme
.
of
(
context
).
accentColor
;
return
new
TabBarSelection
<
IconData
>(
values:
icons
,
final
double
statusBarHeight
=
(
MediaQuery
.
of
(
context
)?.
padding
??
EdgeInsets
.
zero
).
top
;
return
new
TabBarSelection
<
_Page
>(
values:
_pages
,
onChanged:
(
_Page
value
)
{
setState
(()
{
_selectedPage
=
value
;
_selectedPage
.
key
.
currentState
.
scrollTo
(
_scrollOffset
);
});
},
child:
new
Scaffold
(
scrollableKey:
_selectedPage
.
key
,
appBarBehavior:
AppBarBehavior
.
under
,
appBar:
new
AppBar
(
title:
new
Text
(
"Scrollable Tabs"
),
tabBar:
new
TabBar
<
IconData
>(
isScrollable:
true
,
labels:
new
Map
<
IconData
,
TabLabel
>.
fromIterable
(
icons
,
value:
(
IconData
icon
)
=>
new
TabLabel
(
text:
labels
[
icon
],
icon:
icon
)
)
title:
new
Text
(
'Tabs and Scrolling'
),
tabBar:
new
TabBar
<
_Page
>(
labels:
new
Map
<
_Page
,
TabLabel
>.
fromIterable
(
_pages
,
value:
(
_Page
page
)
{
return
new
TabLabel
(
text:
page
.
label
);
})
)
),
body:
new
TabBarView
<
IconData
>(
children:
icons
.
map
((
IconData
icon
)
{
return
new
Container
(
key:
new
ObjectKey
(
icon
),
padding:
const
EdgeInsets
.
all
(
12.0
),
child:
new
Card
(
child:
new
Center
(
child:
new
Icon
(
icon:
icon
,
color:
iconColor
,
size:
128.0
body:
new
TabBarView
<
_Page
>(
children:
_pages
.
map
((
_Page
page
)
{
return
new
Block
(
padding:
new
EdgeInsets
.
only
(
top:
kTextTabBarHeight
+
kToolBarHeight
+
statusBarHeight
),
scrollableKey:
page
.
key
,
onScroll:
(
double
value
)
{
_scrollOffset
=
value
;
},
children:
new
List
<
Widget
>.
generate
(
6
,
(
int
i
)
{
return
new
Container
(
padding:
const
EdgeInsets
.
all
(
8.0
),
height:
192.0
,
child:
new
Card
(
child:
new
Center
(
child:
new
Text
(
'Tab
$page
.label, item
$i
'
)
)
)
)
)
)
;
}
)
);
}).
toList
()
)
...
...
examples/material_gallery/lib/demo/tabs_fab_demo.dart
View file @
7456f6ae
...
...
@@ -34,7 +34,6 @@ class _TabsFabDemoState extends State<TabsFabDemo> {
final
GlobalKey
scaffoldKey
=
new
GlobalKey
();
final
List
<
_Page
>
pages
=
<
_Page
>[
new
_Page
(
label:
'Blue'
,
colors:
Colors
.
indigo
,
icon:
Icons
.
add
),
new
_Page
(
label:
'Too'
,
colors:
Colors
.
indigo
,
icon:
Icons
.
add
),
new
_Page
(
label:
'Eco'
,
colors:
Colors
.
green
,
icon:
Icons
.
create
),
new
_Page
(
label:
'No'
),
new
_Page
(
label:
'Teal'
,
colors:
Colors
.
teal
,
icon:
Icons
.
add
),
...
...
examples/material_gallery/lib/gallery/home.dart
View file @
7456f6ae
...
...
@@ -30,6 +30,7 @@ import '../demo/toggle_controls_demo.dart';
import
'../demo/scrolling_techniques_demo.dart'
;
import
'../demo/slider_demo.dart'
;
import
'../demo/snack_bar_demo.dart'
;
import
'../demo/scrollable_tabs_demo.dart'
;
import
'../demo/tabs_demo.dart'
;
import
'../demo/tabs_fab_demo.dart'
;
import
'../demo/text_field_demo.dart'
;
...
...
@@ -49,14 +50,15 @@ class GalleryHome extends StatefulWidget {
class
GalleryHomeState
extends
State
<
GalleryHome
>
{
@override
Widget
build
(
BuildContext
context
)
{
final
double
appBarHeight
=
128.0
;
return
new
Scaffold
(
appBarHeight:
128.0
,
drawer:
new
GalleryDrawer
(),
appBar:
new
AppBar
(
expandedHeight:
appBarHeight
,
flexibleSpace:
(
BuildContext
context
)
{
return
new
Container
(
padding:
const
EdgeInsets
.
only
(
left:
16.0
,
bottom:
2
4.0
),
height:
128.0
,
padding:
const
EdgeInsets
.
only
(
left:
6
4.0
),
height:
appBarHeight
,
child:
new
Align
(
alignment:
const
FractionalOffset
(
0.0
,
1.0
),
child:
new
Text
(
'Flutter Gallery'
,
style:
Typography
.
white
.
headline
)
...
...
@@ -118,6 +120,7 @@ class GalleryHomeState extends State<GalleryHome> {
new
GalleryDemo
(
title:
'Page Selector'
,
builder:
()
=>
new
PageSelectorDemo
()),
new
GalleryDemo
(
title:
'Persistent Bottom Sheet'
,
builder:
()
=>
new
PersistentBottomSheetDemo
()),
new
GalleryDemo
(
title:
'Progress Indicators'
,
builder:
()
=>
new
ProgressIndicatorDemo
()),
new
GalleryDemo
(
title:
'Scrollable Tabs'
,
builder:
()
=>
new
ScrollableTabsDemo
()),
new
GalleryDemo
(
title:
'Selection Controls'
,
builder:
()
=>
new
ToggleControlsDemo
()),
new
GalleryDemo
(
title:
'Sliders'
,
builder:
()
=>
new
SliderDemo
()),
new
GalleryDemo
(
title:
'SnackBar'
,
builder:
()
=>
new
SnackBarDemo
()),
...
...
examples/material_gallery/lib/gallery/section.dart
View file @
7456f6ae
...
...
@@ -25,6 +25,7 @@ class GallerySection extends StatelessWidget {
}
void
showDemos
(
BuildContext
context
)
{
final
double
statusBarHeight
=
(
MediaQuery
.
of
(
context
)?.
padding
??
EdgeInsets
.
zero
).
top
;
final
ThemeData
theme
=
new
ThemeData
(
brightness:
Theme
.
of
(
context
).
brightness
,
primarySwatch:
colors
...
...
@@ -36,16 +37,16 @@ class GallerySection extends StatelessWidget {
return
new
Theme
(
data:
theme
,
child:
new
Scaffold
(
appBarHeight:
appBarHeight
,
appBarBehavior:
AppBarBehavior
.
under
,
scrollableKey:
scrollableKey
,
appBar:
new
AppBar
(
expandedHeight:
appBarHeight
,
flexibleSpace:
(
BuildContext
context
)
=>
new
FlexibleSpaceBar
(
title:
new
Text
(
title
))
),
body:
new
Material
(
child:
new
MaterialList
(
scrollableKey:
scrollableKey
,
scrollablePadding:
new
EdgeInsets
.
only
(
top:
appBarHeight
),
scrollablePadding:
new
EdgeInsets
.
only
(
top:
appBarHeight
+
statusBarHeight
),
type:
MaterialListType
.
oneLine
,
children:
(
demos
??
const
<
GalleryDemo
>[]).
map
((
GalleryDemo
demo
)
{
return
new
ListItem
(
...
...
packages/flutter/lib/src/material/app_bar.dart
View file @
7456f6ae
...
...
@@ -8,6 +8,7 @@ import 'constants.dart';
import
'icon_theme.dart'
;
import
'icon_theme_data.dart'
;
import
'material.dart'
;
import
'tabs.dart'
;
import
'theme.dart'
;
import
'typography.dart'
;
...
...
@@ -23,8 +24,16 @@ class AppBar extends StatelessWidget {
this
.
elevation
:
4
,
this
.
backgroundColor
,
this
.
textTheme
,
this
.
padding
:
EdgeInsets
.
zero
})
:
super
(
key:
key
)
{
this
.
padding
:
EdgeInsets
.
zero
,
double
expandedHeight
,
double
collapsedHeight
,
double
minimumHeight
,
double
actualHeight
})
:
_expandedHeight
=
expandedHeight
,
_collapsedHeight
=
collapsedHeight
,
_minimumHeight
=
minimumHeight
,
_actualHeight
=
actualHeight
,
super
(
key:
key
)
{
assert
((
flexibleSpace
!=
null
)
?
tabBar
==
null
:
true
);
assert
((
tabBar
!=
null
)
?
flexibleSpace
==
null
:
true
);
}
...
...
@@ -34,11 +43,15 @@ class AppBar extends StatelessWidget {
final
List
<
Widget
>
actions
;
final
WidgetBuilder
flexibleSpace
;
final
double
foregroundOpacity
;
final
Widget
tabBar
;
final
TabBar
<
dynamic
>
tabBar
;
final
int
elevation
;
final
Color
backgroundColor
;
final
TextTheme
textTheme
;
final
EdgeInsets
padding
;
final
double
_expandedHeight
;
final
double
_collapsedHeight
;
final
double
_minimumHeight
;
final
double
_actualHeight
;
AppBar
copyWith
({
Key
key
,
...
...
@@ -50,7 +63,10 @@ class AppBar extends StatelessWidget {
int
elevation
,
Color
backgroundColor
,
TextTheme
textTheme
,
EdgeInsets
padding
EdgeInsets
padding
,
double
expandedHeight
,
double
collapsedHeight
,
double
actualHeight
})
{
return
new
AppBar
(
key:
key
??
this
.
key
,
...
...
@@ -63,37 +79,56 @@ class AppBar extends StatelessWidget {
elevation:
elevation
??
this
.
elevation
,
backgroundColor:
backgroundColor
??
this
.
backgroundColor
,
textTheme:
textTheme
??
this
.
textTheme
,
padding:
padding
??
this
.
padding
padding:
padding
??
this
.
padding
,
expandedHeight:
expandedHeight
??
this
.
_expandedHeight
,
collapsedHeight:
collapsedHeight
??
this
.
_collapsedHeight
,
actualHeight:
actualHeight
??
this
.
_actualHeight
);
}
double
get
_tabBarHeight
=>
tabBar
==
null
?
null
:
tabBar
.
minimumHeight
;
double
get
_toolBarHeight
=>
kToolBarHeight
;
double
get
expandedHeight
=>
_expandedHeight
??
(
_toolBarHeight
+
(
_tabBarHeight
??
0.0
));
double
get
collapsedHeight
=>
_collapsedHeight
??
(
_toolBarHeight
+
(
_tabBarHeight
??
0.0
));
double
get
minimumHeight
=>
_minimumHeight
??
_tabBarHeight
??
_toolBarHeight
;
double
get
actualHeight
=>
_actualHeight
??
expandedHeight
;
// Defines the opacity of the toolbar's text and icons.
double
_toolBarOpacity
(
double
statusBarHeight
)
{
return
((
actualHeight
-
(
_tabBarHeight
??
0.0
)
-
statusBarHeight
)
/
_toolBarHeight
).
clamp
(
0.0
,
1.0
);
}
double
_tabBarOpacity
(
double
statusBarHeight
)
{
final
double
tabBarHeight
=
_tabBarHeight
??
0.0
;
return
((
actualHeight
-
statusBarHeight
)
/
tabBarHeight
).
clamp
(
0.0
,
1.0
);
}
@override
Widget
build
(
BuildContext
context
)
{
Color
color
=
backgroundColor
;
IconThemeData
iconThemeData
;
TextStyle
centerStyle
=
textTheme
?.
title
;
TextStyle
sideStyle
=
textTheme
?.
body1
;
if
(
color
==
null
||
iconThemeData
==
null
||
textTheme
==
null
)
{
ThemeData
themeData
=
Theme
.
of
(
context
);
color
??=
themeData
.
primaryColor
;
iconThemeData
??=
themeData
.
primaryIconTheme
;
TextTheme
primaryTextTheme
=
themeData
.
primaryTextTheme
;
centerStyle
??=
primaryTextTheme
.
title
;
sideStyle
??=
primaryTextTheme
.
body2
;
}
final
double
statusBarHeight
=
(
MediaQuery
.
of
(
context
)?.
padding
??
EdgeInsets
.
zero
).
top
;
final
ThemeData
theme
=
Theme
.
of
(
context
);
IconThemeData
iconTheme
=
theme
.
primaryIconTheme
;
TextStyle
centerStyle
=
textTheme
?.
title
??
theme
.
primaryTextTheme
.
title
;
TextStyle
sideStyle
=
textTheme
?.
body1
??
theme
.
primaryTextTheme
.
body1
;
if
(
foregroundOpacity
!=
1.0
)
{
final
int
alpha
=
(
foregroundOpacity
.
clamp
(
0.0
,
1.0
)
*
255.0
).
round
();
final
double
toolBarOpacity
=
_toolBarOpacity
(
statusBarHeight
);
if
(
toolBarOpacity
!=
1.0
)
{
final
double
opacity
=
const
Interval
(
0.25
,
1.0
,
curve:
Curves
.
ease
).
transform
(
toolBarOpacity
);
if
(
centerStyle
?.
color
!=
null
)
centerStyle
=
centerStyle
.
copyWith
(
color:
centerStyle
.
color
.
with
Alpha
(
alpha
));
centerStyle
=
centerStyle
.
copyWith
(
color:
centerStyle
.
color
.
with
Opacity
(
opacity
));
if
(
sideStyle
?.
color
!=
null
)
sideStyle
=
sideStyle
.
copyWith
(
color:
sideStyle
.
color
.
withAlpha
(
alpha
));
if
(
iconThemeData
!=
null
)
{
iconThemeData
=
new
IconThemeData
(
opacity:
foregroundOpacity
*
iconThemeData
.
clampedOpacity
,
color:
iconThemeData
.
color
sideStyle
=
sideStyle
.
copyWith
(
color:
sideStyle
.
color
.
withOpacity
(
opacity
));
if
(
iconTheme
!=
null
)
{
iconTheme
=
new
IconThemeData
(
opacity:
opacity
*
iconTheme
.
clampedOpacity
,
color:
iconTheme
.
color
);
}
}
...
...
@@ -112,59 +147,72 @@ class AppBar extends StatelessWidget {
if
(
actions
!=
null
)
toolBarRow
.
addAll
(
actions
);
Widget
appBar
=
new
SizedBox
(
height:
kToolBarHeight
,
child:
new
IconTheme
(
data:
iconTheme
,
child:
new
DefaultTextStyle
(
style:
sideStyle
,
child:
new
Row
(
children:
toolBarRow
)
)
)
);
final
double
tabBarOpacity
=
_tabBarOpacity
(
statusBarHeight
);
if
(
tabBar
!=
null
)
{
appBar
=
new
Column
(
children:
<
Widget
>[
appBar
,
tabBarOpacity
==
1.0
?
tabBar
:
new
Opacity
(
child:
tabBar
,
opacity:
const
Interval
(
0.25
,
1.0
,
curve:
Curves
.
ease
).
transform
(
tabBarOpacity
)
)
]
);
}
EdgeInsets
combinedPadding
=
new
EdgeInsets
.
symmetric
(
horizontal:
8.0
);
if
(
padding
!=
null
)
combinedPadding
+=
padding
;
// If the toolBar's height shrinks below toolBarHeight, it will be clipped and bottom
// justified. This is so that the toolbar appears to move upwards as its height is reduced.
final
double
toolBarHeight
=
kToolBarHeight
+
combinedPadding
.
top
+
combinedPadding
.
bottom
;
final
Widget
toolBar
=
new
ConstrainedBox
(
constraints:
new
BoxConstraints
(
maxHeight:
toolBarHeight
),
// If the appBar's height shrinks below collapsedHeight, it will be clipped and bottom
// justified. This is so that the toolBar/tabBar appear to move upwards as the appBar's
// height is reduced.
final
double
paddedCollapsedHeight
=
collapsedHeight
+
combinedPadding
.
top
+
combinedPadding
.
bottom
;
appBar
=
new
ConstrainedBox
(
constraints:
new
BoxConstraints
(
maxHeight:
paddedCollapsedHeight
),
child:
new
Padding
(
padding:
new
EdgeInsets
.
only
(
left:
combinedPadding
.
left
,
right:
combinedPadding
.
right
),
child:
new
ClipRect
(
child:
new
OverflowBox
(
alignment:
const
FractionalOffset
(
0.0
,
1.0
),
// bottom justify
minHeight:
toolBarHeight
,
maxHeight:
toolBarHeight
,
child:
new
DefaultTextStyle
(
style:
sideStyle
,
child:
new
Padding
(
padding:
new
EdgeInsets
.
only
(
top:
combinedPadding
.
top
,
bottom:
combinedPadding
.
bottom
),
child:
new
Row
(
children:
toolBarRow
)
)
minHeight:
paddedCollapsedHeight
,
maxHeight:
paddedCollapsedHeight
,
child:
new
Padding
(
padding:
new
EdgeInsets
.
only
(
top:
combinedPadding
.
top
,
bottom:
combinedPadding
.
bottom
),
child:
appBar
)
)
)
)
);
Widget
appBar
=
toolBar
;
if
(
tabBar
!=
null
)
{
appBar
=
new
Column
(
mainAxisAlignment:
MainAxisAlignment
.
collapse
,
children:
<
Widget
>[
toolBar
,
tabBar
]
);
}
else
if
(
flexibleSpace
!=
null
)
{
if
(
flexibleSpace
!=
null
)
{
appBar
=
new
Stack
(
children:
<
Widget
>[
flexibleSpace
(
context
),
new
Align
(
child:
tool
Bar
,
alignment:
const
FractionalOffset
(
0.0
,
0.0
))
new
Align
(
child:
app
Bar
,
alignment:
const
FractionalOffset
(
0.0
,
0.0
))
]
);
}
Widget
contents
=
new
Material
(
color:
c
olor
,
appBar
=
new
Material
(
color:
backgroundColor
??
theme
.
primaryC
olor
,
elevation:
elevation
,
child:
appBar
);
if
(
iconThemeData
!=
null
)
contents
=
new
IconTheme
(
data:
iconThemeData
,
child:
contents
);
return
contents
;
return
appBar
;
}
}
packages/flutter/lib/src/material/constants.dart
View file @
7456f6ae
...
...
@@ -13,8 +13,8 @@ const double kToolBarHeight = 56.0;
const
double
kExtendedAppBarHeight
=
128.0
;
const
double
kTextTabBarHeight
=
48.0
;
const
double
kIconTabBarHeight
=
48
.0
;
const
double
kText
andIconTabBarHeight
=
72
.0
;
const
double
kIconTabBarHeight
=
26
.0
;
const
double
kText
AndIconTabBarHeight
=
74
.0
;
// https://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keylines-keylines-spacing
const
double
kListTitleHeight
=
72.0
;
...
...
packages/flutter/lib/src/material/flexible_space_bar.dart
View file @
7456f6ae
...
...
@@ -25,10 +25,10 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
@override
Widget
build
(
BuildContext
context
)
{
assert
(
debugCheckHasScaffold
(
context
));
final
double
appBarHeight
=
Scaffold
.
of
(
context
).
appBarHeight
;
final
double
statusBarHeight
=
(
MediaQuery
.
of
(
context
)?.
padding
??
EdgeInsets
.
zero
).
top
;
final
Animation
<
double
>
animation
=
Scaffold
.
of
(
context
).
appBarAnimation
;
final
EdgeInsets
toolBarPadding
=
MediaQuery
.
of
(
context
)?.
padding
??
EdgeInsets
.
zero
;
final
double
toolBarHeight
=
kToolBarHeight
+
toolBarPadding
.
top
;
final
double
appBarHeight
=
Scaffold
.
of
(
context
).
appBarHeight
+
statusBarHeight
;
final
double
toolBarHeight
=
kToolBarHeight
+
statusBarHeight
;
final
List
<
Widget
>
children
=
<
Widget
>[];
// background image
...
...
@@ -46,7 +46,10 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
right:
0.0
,
child:
new
Opacity
(
opacity:
new
Tween
<
double
>(
begin:
1.0
,
end:
0.0
).
evaluate
(
opacityCurve
),
child:
config
.
image
child:
new
SizedBox
(
height:
appBarHeight
+
statusBarHeight
,
child:
config
.
image
)
)
));
}
...
...
@@ -64,7 +67,7 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
color:
titleStyle
.
color
.
withAlpha
(
new
Tween
<
double
>(
begin:
255.0
,
end:
0.0
).
evaluate
(
opacityCurve
).
toInt
())
);
final
double
yAlignStart
=
1.0
;
final
double
yAlignEnd
=
(
toolBarPadding
.
top
+
kToolBarHeight
/
2.0
)
/
toolBarHeight
;
final
double
yAlignEnd
=
(
statusBarHeight
+
kToolBarHeight
/
2.0
)
/
toolBarHeight
;
final
double
scaleAndAlignEnd
=
(
appBarHeight
-
toolBarHeight
)
/
appBarHeight
;
final
CurvedAnimation
scaleAndAlignCurve
=
new
CurvedAnimation
(
parent:
animation
,
...
...
packages/flutter/lib/src/material/scaffold.dart
View file @
7456f6ae
...
...
@@ -10,7 +10,6 @@ import 'package:flutter/widgets.dart';
import
'app_bar.dart'
;
import
'bottom_sheet.dart'
;
import
'constants.dart'
;
import
'drawer.dart'
;
import
'icons.dart'
;
import
'icon_button.dart'
;
...
...
@@ -211,11 +210,9 @@ class Scaffold extends StatefulWidget {
this
.
floatingActionButton
,
this
.
drawer
,
this
.
scrollableKey
,
this
.
appBarBehavior
:
AppBarBehavior
.
anchor
,
this
.
appBarHeight
this
.
appBarBehavior
:
AppBarBehavior
.
anchor
})
:
super
(
key:
key
)
{
assert
((
appBarBehavior
==
AppBarBehavior
.
scroll
)
?
scrollableKey
!=
null
:
true
);
assert
((
appBarBehavior
==
AppBarBehavior
.
scroll
)
?
appBarHeight
!=
null
&&
appBarHeight
>
kToolBarHeight
:
true
);
}
final
AppBar
appBar
;
...
...
@@ -224,7 +221,6 @@ class Scaffold extends StatefulWidget {
final
Widget
drawer
;
final
Key
scrollableKey
;
final
AppBarBehavior
appBarBehavior
;
final
double
appBarHeight
;
/// The state from the closest instance of this class that encloses the given context.
static
ScaffoldState
of
(
BuildContext
context
)
=>
context
.
ancestorStateOfType
(
const
TypeMatcher
<
ScaffoldState
>());
...
...
@@ -241,7 +237,7 @@ class ScaffoldState extends State<Scaffold> {
Animation
<
double
>
get
appBarAnimation
=>
_appBarController
.
view
;
double
get
appBarHeight
=>
config
.
appBar
Height
;
double
get
appBarHeight
=>
config
.
appBar
?.
expandedHeight
??
0.0
;
// DRAWER API
...
...
@@ -401,11 +397,10 @@ class ScaffoldState extends State<Scaffold> {
bool
_shouldShowBackArrow
;
Widget
_getModifiedAppBar
({
EdgeInsets
padding
,
double
foregroundOpacity:
1.0
,
int
elevation
})
{
Widget
_getModifiedAppBar
({
EdgeInsets
padding
,
int
elevation
,
double
actualHeight
})
{
AppBar
appBar
=
config
.
appBar
;
if
(
appBar
==
null
)
return
null
;
EdgeInsets
appBarPadding
=
new
EdgeInsets
.
only
(
top:
padding
.
top
);
Widget
leading
=
appBar
.
leading
;
if
(
leading
==
null
)
{
if
(
config
.
drawer
!=
null
)
{
...
...
@@ -427,9 +422,9 @@ class ScaffoldState extends State<Scaffold> {
}
return
appBar
.
copyWith
(
elevation:
elevation
??
appBar
.
elevation
??
4
,
padding:
appBarPadding
,
foregroundOpacity:
foregroundOpacity
,
leading:
leading
padding:
new
EdgeInsets
.
only
(
top:
padding
.
top
)
,
leading:
leading
,
actualHeight:
actualHeight
);
}
...
...
@@ -438,73 +433,66 @@ class ScaffoldState extends State<Scaffold> {
double
_floatingAppBarHeight
=
0.0
;
bool
_handleScrollNotification
(
ScrollNotification
notification
)
{
final
double
newScrollOffset
=
notification
.
scrollable
.
scrollOffset
;
if
(
config
.
scrollableKey
!=
null
&&
config
.
scrollableKey
==
notification
.
scrollable
.
config
.
key
)
if
(
config
.
scrollableKey
!=
null
&&
config
.
scrollableKey
==
notification
.
scrollable
.
config
.
key
)
{
final
double
newScrollOffset
=
notification
.
scrollable
.
scrollOffset
;
setState
(()
{
_scrollOffsetDelta
=
_scrollOffset
-
newScrollOffset
;
_scrollOffset
=
newScrollOffset
;
});
}
return
false
;
}
double
_appBarOpacity
(
double
progress
)
{
// The value of progress is 1.0 if the entire (padded) app bar is visible, 0.0
// if the app bar's height is zero.
return
new
Tween
<
double
>(
begin:
0.0
,
end:
1.0
).
evaluate
(
new
CurvedAnimation
(
parent:
new
AnimationController
()..
value
=
progress
.
clamp
(
0.0
,
1.0
),
curve:
new
Interval
(
0.50
,
1.0
)
));
}
Widget
_buildAnchoredAppBar
(
double
toolBarHeight
,
EdgeInsets
toolBarPadding
)
{
Widget
_buildAnchoredAppBar
(
double
expandedHeight
,
double
height
,
EdgeInsets
padding
)
{
// Drive _appBarController to the point where the flexible space has disappeared.
_appBarController
.
value
=
(
appBarHeight
-
toolBarHeight
)
/
appBar
Height
;
_appBarController
.
value
=
(
expandedHeight
-
height
)
/
expanded
Height
;
return
new
SizedBox
(
height:
toolBarH
eight
,
child:
_getModifiedAppBar
(
padding:
toolBarPadding
)
height:
h
eight
,
child:
_getModifiedAppBar
(
padding:
padding
,
actualHeight:
height
)
);
}
Widget
_buildScrollableAppBar
(
BuildContext
context
)
{
final
EdgeInsets
toolBarPadding
=
MediaQuery
.
of
(
context
)?.
padding
??
EdgeInsets
.
zero
;
final
double
toolBarHeight
=
kToolBarHeight
+
toolBarPadding
.
top
;
final
EdgeInsets
padding
=
MediaQuery
.
of
(
context
)?.
padding
??
EdgeInsets
.
zero
;
final
double
expandedHeight
=
(
config
.
appBar
?.
expandedHeight
??
0.0
)
+
padding
.
top
;
final
double
collapsedHeight
=
(
config
.
appBar
?.
collapsedHeight
??
0.0
)
+
padding
.
top
;
final
double
minimumHeight
=
(
config
.
appBar
?.
minimumHeight
??
0.0
)
+
padding
.
top
;
Widget
appBar
;
if
(
_scrollOffset
<=
appBarHeight
&&
_scrollOffset
>=
appBarHeight
-
toolBar
Height
)
{
// scrolled to the top,
only the toolbar is
(partially) visible.
if
(
_scrollOffset
<=
expandedHeight
&&
_scrollOffset
>=
expandedHeight
-
minimum
Height
)
{
// scrolled to the top,
flexible space collapsed, only the toolbar and tabbar are
(partially) visible.
if
(
config
.
appBarBehavior
==
AppBarBehavior
.
under
)
{
appBar
=
_buildAnchoredAppBar
(
toolBarHeight
,
toolBarP
adding
);
appBar
=
_buildAnchoredAppBar
(
expandedHeight
,
minimumHeight
,
p
adding
);
}
else
{
final
double
height
=
math
.
max
(
_floatingAppBarHeight
,
appBarHeight
-
_scrollOffset
);
final
double
opacity
=
_appBarOpacity
(
1.0
-
((
toolBarHeight
-
height
)
/
toolBarHeight
));
_appBarController
.
value
=
(
appBarHeight
-
height
)
/
appBarHeight
;
final
double
height
=
math
.
max
(
_floatingAppBarHeight
,
expandedHeight
-
_scrollOffset
);
_appBarController
.
value
=
(
expandedHeight
-
height
)
/
expandedHeight
;
appBar
=
new
SizedBox
(
height:
height
,
child:
_getModifiedAppBar
(
padding:
toolBarPadding
,
foregroundOpacity:
opacity
)
child:
_getModifiedAppBar
(
padding:
padding
,
actualHeight:
height
)
);
}
}
else
if
(
_scrollOffset
>
appBar
Height
)
{
}
else
if
(
_scrollOffset
>
expanded
Height
)
{
// scrolled past the entire app bar, maybe show the "floating" toolbar.
if
(
config
.
appBarBehavior
==
AppBarBehavior
.
under
)
{
appBar
=
_buildAnchoredAppBar
(
toolBarHeight
,
toolBarP
adding
);
appBar
=
_buildAnchoredAppBar
(
expandedHeight
,
minimumHeight
,
p
adding
);
}
else
{
_floatingAppBarHeight
=
(
_floatingAppBarHeight
+
_scrollOffsetDelta
).
clamp
(
0.0
,
toolBarHeight
);
final
double
toolBarOpacity
=
_appBarOpacity
(
_floatingAppBarHeight
/
toolBarHeight
);
_appBarController
.
value
=
(
appBarHeight
-
_floatingAppBarHeight
)
/
appBarHeight
;
_floatingAppBarHeight
=
(
_floatingAppBarHeight
+
_scrollOffsetDelta
).
clamp
(
0.0
,
collapsedHeight
);
_appBarController
.
value
=
(
expandedHeight
-
_floatingAppBarHeight
)
/
expandedHeight
;
appBar
=
new
SizedBox
(
height:
_floatingAppBarHeight
,
child:
_getModifiedAppBar
(
padding:
toolBarPadding
,
foregroundOpacity:
toolBarOpacity
)
child:
_getModifiedAppBar
(
padding:
padding
,
actualHeight:
_floatingAppBarHeight
)
);
}
}
else
{
// _scrollOffset <
appBarHeight - appBarHeight, scrolled to the top, flexible space is visible
final
double
height
=
appBarHeight
-
_scrollOffset
.
clamp
(
0.0
,
appBar
Height
);
_appBarController
.
value
=
(
appBarHeight
-
height
)
/
appBar
Height
;
// _scrollOffset <
expandedHeight - collapsedHeight, scrolled to the top, flexible space is visible]
final
double
height
=
expandedHeight
-
_scrollOffset
.
clamp
(
0.0
,
expanded
Height
);
_appBarController
.
value
=
(
expandedHeight
-
height
)
/
expanded
Height
;
appBar
=
new
SizedBox
(
height:
height
,
child:
_getModifiedAppBar
(
padding:
toolBarPadding
,
elevation:
0
)
child:
_getModifiedAppBar
(
padding:
padding
,
elevation:
0
,
actualHeight:
height
)
);
_floatingAppBarHeight
=
0.0
;
}
return
appBar
;
...
...
@@ -528,9 +516,10 @@ class ScaffoldState extends State<Scaffold> {
final
List
<
LayoutId
>
children
=
new
List
<
LayoutId
>();
_addIfNonNull
(
children
,
config
.
body
,
_ScaffoldSlot
.
body
);
if
(
config
.
appBarBehavior
==
AppBarBehavior
.
anchor
)
{
final
double
expandedHeight
=
(
config
.
appBar
?.
expandedHeight
??
0.0
)
+
padding
.
top
;
final
Widget
appBar
=
new
ConstrainedBox
(
child:
_getModifiedAppBar
(
padding:
padding
),
constraints:
new
BoxConstraints
(
maxHeight:
config
.
appBarHeight
??
kExtendedAppBarHeight
+
padding
.
top
)
child:
_getModifiedAppBar
(
padding:
padding
,
actualHeight:
expandedHeight
),
constraints:
new
BoxConstraints
(
maxHeight:
expandedHeight
)
);
_addIfNonNull
(
children
,
appBar
,
_ScaffoldSlot
.
appBar
);
}
...
...
packages/flutter/lib/src/material/tabs.dart
View file @
7456f6ae
...
...
@@ -592,6 +592,14 @@ class TabBar<T> extends Scrollable {
final
Map
<
T
,
TabLabel
>
labels
;
final
bool
isScrollable
;
double
get
minimumHeight
{
for
(
TabLabel
label
in
labels
.
values
)
{
if
(
label
.
text
!=
null
&&
(
label
.
icon
!=
null
||
label
.
iconBuilder
!=
null
))
return
_kTextAndIconTabHeight
+
_kTabIndicatorHeight
;
}
return
_kTabHeight
+
_kTabIndicatorHeight
;
}
@override
_TabBarState
<
T
>
createState
()
=>
new
_TabBarState
<
T
>();
}
...
...
@@ -810,9 +818,9 @@ class _TabBarState<T> extends ScrollableState<TabBar<T>> implements TabBarSelect
indicatorColor
=
Colors
.
white
;
}
TextStyle
textStyle
=
themeData
.
primaryTextTheme
.
body
1
;
TextStyle
textStyle
=
themeData
.
primaryTextTheme
.
body
2
;
IconThemeData
iconTheme
=
themeData
.
primaryIconTheme
;
Color
textColor
=
themeData
.
primaryTextTheme
.
body
1
.
color
.
withAlpha
(
0xB2
);
// 70% alpha
Color
textColor
=
themeData
.
primaryTextTheme
.
body
2
.
color
.
withAlpha
(
0xB2
);
// 70% alpha
List
<
Widget
>
tabs
=
<
Widget
>[];
bool
textAndIcons
=
false
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment