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
8475e0b2
Commit
8475e0b2
authored
Sep 20, 2017
by
xster
Committed by
GitHub
Sep 20, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Split Cupertino nav bar into a static one and a slivers one (#12102)
parent
987b2056
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
205 additions
and
60 deletions
+205
-60
nav_bar.dart
packages/flutter/lib/src/cupertino/nav_bar.dart
+125
-50
scaffold.dart
packages/flutter/lib/src/cupertino/scaffold.dart
+2
-4
nav_bar_test.dart
packages/flutter/test/cupertino/nav_bar_test.dart
+78
-6
No files found.
packages/flutter/lib/src/cupertino/nav_bar.dart
View file @
8475e0b2
...
...
@@ -29,9 +29,10 @@ const Color _kDefaultNavBarBackgroundColor = const Color(0xCCF8F8F8);
const
Color
_kDefaultNavBarBorderColor
=
const
Color
(
0x4C000000
);
const
TextStyle
_kLargeTitleTextStyle
=
const
TextStyle
(
fontFamily:
'.SF UI Text'
,
fontSize:
34.0
,
fontWeight:
FontWeight
.
bold
,
letterSpacing:
0.41
,
fontWeight:
FontWeight
.
w700
,
letterSpacing:
-
1.4
,
color:
CupertinoColors
.
black
,
);
...
...
@@ -49,13 +50,13 @@ const TextStyle _kLargeTitleTextStyle = const TextStyle(
/// If the given [backgroundColor]'s opacity is not 1.0 (which is the case by
/// default), it will produce a blurring effect to the content behind it.
///
/// Enabling [largeTitle] will create a scrollable second row showing the title
/// in a larger font introduced in iOS 11. The [middle] widget must be a text
/// and the [CupertinoNavigationBar] must be placed in a sliver group in this case.
/// See also:
///
/// * [CupertinoSliverNavigationBar] for a nav bar to be placed in a sliver and
/// that supports iOS 11 style large titles.
//
// TODO(xster): document automatic addition of a CupertinoBackButton.
// TODO(xster): add sample code using icons.
// TODO(xster): document integration into a CupertinoScaffold.
class
CupertinoNavigationBar
extends
StatelessWidget
implements
PreferredSizeWidget
{
/// Creates a navigation bar in the iOS style.
const
CupertinoNavigationBar
({
...
...
@@ -65,7 +66,6 @@ class CupertinoNavigationBar extends StatelessWidget implements PreferredSizeWid
this
.
trailing
,
this
.
backgroundColor
:
_kDefaultNavBarBackgroundColor
,
this
.
actionsForegroundColor
:
CupertinoColors
.
activeBlue
,
this
.
largeTitle
:
false
,
})
:
assert
(
middle
!=
null
,
'There must be a middle widget, usually a title.'
),
super
(
key:
key
);
...
...
@@ -98,50 +98,115 @@ class CupertinoNavigationBar extends StatelessWidget implements PreferredSizeWid
/// True if the nav bar's background color has no transparency.
bool
get
opaque
=>
backgroundColor
.
alpha
==
0xFF
;
/// Use iOS 11 style large title navigation bars.
///
/// When true, the navigation bar will split into 2 sections. The static
/// top 44px section will be wrapped in a SliverPersistentHeader and a
/// second scrollable section behind it will show and replace the `middle`
/// text in a larger font when scrolled down.
///
/// Navigation bars with large titles must be used in a sliver group such
/// as [CustomScrollView].
final
bool
largeTitle
;
@override
Size
get
preferredSize
=>
const
Size
.
fromHeight
(
_kNavBarPersistentHeight
);
Size
get
preferredSize
{
return
opaque
?
const
Size
.
fromHeight
(
_kNavBarPersistentHeight
)
:
Size
.
zero
;
}
@override
Widget
build
(
BuildContext
context
)
{
assert
(
!
largeTitle
||
middle
is
Text
,
"largeTitle mode is only possible when 'middle' is a Text widget"
return
_wrapWithBackground
(
backgroundColor:
backgroundColor
,
child:
new
_CupertinoPersistentNavigationBar
(
leading:
leading
,
middle:
middle
,
trailing:
trailing
,
actionsForegroundColor:
actionsForegroundColor
,
),
);
}
}
if
(!
largeTitle
)
{
return
_wrapWithBackground
(
/// An iOS-styled navigation bar with iOS 11 style large titles using slivers.
///
/// The [CupertinoSliverNavigationBar] must be placed in a sliver group such
/// as the [CustomScrollView].
///
/// This navigation bar consists of 2 sections, a pinned static section built
/// using [CupertinoNavigationBar] on top and a sliding section containing
/// iOS 11 style large titles below it.
///
/// It should be placed at top of the screen and automatically accounts for
/// the OS's status bar.
///
/// Minimally, a [largeTitle] [Text] will appear in the middle of the app bar
/// when the sliver is collapsed and transfer to the slidable below in larger font
/// when the sliver is expanded.
///
/// For advanced uses, an optional [middle] widget can be supplied to show a different
/// widget in the middle of the nav bar when the sliver is collapsed.
///
/// See also:
///
/// * [CupertinoNavigationBar] a static iOS nav bar that doesn't have a slidable
/// large title section.
class
CupertinoSliverNavigationBar
extends
StatelessWidget
{
const
CupertinoSliverNavigationBar
({
Key
key
,
@required
this
.
largeTitle
,
this
.
leading
,
this
.
middle
,
this
.
trailing
,
this
.
backgroundColor
:
_kDefaultNavBarBackgroundColor
,
this
.
actionsForegroundColor
:
CupertinoColors
.
activeBlue
,
})
:
assert
(
largeTitle
!=
null
,
'There must be a largeTitle Text'
),
super
(
key:
key
);
/// The navigation bar's title.
///
/// This text will appear in the top static navigation bar when collapsed and
/// in the bottom slidable in a larger font when expanded.
final
Text
largeTitle
;
/// Widget to place at the start of the static nav bar. Normally a back button
/// for a normal page or a cancel button for full page dialogs.
///
/// This widget is visible in both collapsed and expanded states.
final
Widget
leading
;
/// An override widget to place in the middle of the static nav bar.
///
/// This widget is visible in both collapsed and expanded states. The text
/// supplied in [largeTitle] will no longer appear in collapsed state.
final
Widget
middle
;
/// Widget to place at the end of the static nav bar. Normally additional actions
/// taken on the page such as a search or edit function.
///
/// This widget is visible in both collapsed and expanded states.
final
Widget
trailing
;
// TODO(xster): implement support for double row nav bars.
/// The background color of the nav bar. If it contains transparency, the
/// tab bar will automatically produce a blurring effect to the content
/// behind it.
final
Color
backgroundColor
;
/// Default color used for text and icons of the [leading] and [trailing]
/// widgets in the nav bar.
///
/// The default color for text in the [middle] slot is always black, as per
/// iOS standard design.
final
Color
actionsForegroundColor
;
/// True if the nav bar's background color has no transparency.
bool
get
opaque
=>
backgroundColor
.
alpha
==
0xFF
;
@override
Widget
build
(
BuildContext
context
)
{
return
new
SliverPersistentHeader
(
pinned:
true
,
// iOS navigation bars are always pinned.
delegate:
new
_CupertinoLargeTitleNavigationBarSliverDelegate
(
persistentHeight:
_kNavBarPersistentHeight
+
MediaQuery
.
of
(
context
).
padding
.
top
,
title:
largeTitle
,
leading:
leading
,
middle:
middle
,
trailing:
trailing
,
backgroundColor:
backgroundColor
,
child:
new
_CupertinoPersistentNavigationBar
(
leading:
leading
,
middle:
middle
,
trailing:
trailing
,
actionsForegroundColor:
actionsForegroundColor
,
),
);
}
else
{
return
new
SliverPersistentHeader
(
pinned:
true
,
// iOS navigation bars are always pinned.
delegate:
new
_CupertinoLargeTitleNavigationBarSliverDelegate
(
persistentHeight:
_kNavBarPersistentHeight
+
MediaQuery
.
of
(
context
).
padding
.
top
,
leading:
leading
,
middle:
middle
,
trailing:
trailing
,
backgroundColor:
backgroundColor
,
actionsForegroundColor:
actionsForegroundColor
,
),
);
}
actionsForegroundColor:
actionsForegroundColor
,
),
);
}
}
...
...
@@ -206,6 +271,7 @@ class _CupertinoPersistentNavigationBar extends StatelessWidget implements Prefe
@override
Widget
build
(
BuildContext
context
)
{
final
TextStyle
actionsStyle
=
new
TextStyle
(
fontFamily:
'.SF UI Text'
,
fontSize:
17.0
,
letterSpacing:
-
0.24
,
color:
actionsForegroundColor
,
...
...
@@ -224,7 +290,11 @@ class _CupertinoPersistentNavigationBar extends StatelessWidget implements Prefe
// Let the middle be black rather than `actionsForegroundColor` in case
// it's a plain text title.
final
Widget
styledMiddle
=
middle
==
null
?
null
:
DefaultTextStyle
.
merge
(
style:
actionsStyle
.
copyWith
(
color:
CupertinoColors
.
black
),
style:
actionsStyle
.
copyWith
(
fontWeight:
FontWeight
.
w600
,
letterSpacing:
-
0.72
,
color:
CupertinoColors
.
black
,
),
child:
middle
,
);
...
...
@@ -268,8 +338,9 @@ class _CupertinoPersistentNavigationBar extends StatelessWidget implements Prefe
class
_CupertinoLargeTitleNavigationBarSliverDelegate
extends
SliverPersistentHeaderDelegate
{
const
_CupertinoLargeTitleNavigationBarSliverDelegate
({
@required
this
.
persistentHeight
,
@required
this
.
title
,
this
.
leading
,
@required
this
.
middle
,
this
.
middle
,
this
.
trailing
,
this
.
backgroundColor
,
this
.
actionsForegroundColor
,
...
...
@@ -277,9 +348,11 @@ class _CupertinoLargeTitleNavigationBarSliverDelegate extends SliverPersistentHe
final
double
persistentHeight
;
final
Text
title
;
final
Widget
leading
;
final
Tex
t
middle
;
final
Widge
t
middle
;
final
Widget
trailing
;
...
...
@@ -300,9 +373,11 @@ class _CupertinoLargeTitleNavigationBarSliverDelegate extends SliverPersistentHe
final
_CupertinoPersistentNavigationBar
persistentNavigationBar
=
new
_CupertinoPersistentNavigationBar
(
leading:
leading
,
middle:
middle
,
middle:
middle
??
title
,
trailing:
trailing
,
middleVisible:
!
showLargeTitle
,
// If middle widget exists, always show it. Otherwise, show title
// when collapsed.
middleVisible:
middle
!=
null
?
null
:
!
showLargeTitle
,
actionsForegroundColor:
actionsForegroundColor
,
);
...
...
@@ -336,7 +411,7 @@ class _CupertinoLargeTitleNavigationBarSliverDelegate extends SliverPersistentHe
child:
new
AnimatedOpacity
(
opacity:
showLargeTitle
?
1.0
:
0.0
,
duration:
_kNavBarTitleFadeDuration
,
child:
midd
le
,
child:
tit
le
,
)
),
),
...
...
packages/flutter/lib/src/cupertino/scaffold.dart
View file @
8475e0b2
...
...
@@ -114,11 +114,9 @@ class _CupertinoScaffoldState extends State<CupertinoScaffold> {
/// on whether the middle widget should slide behind translucent bars.
Widget
_padMiddle
(
Widget
middle
)
{
double
topPadding
=
0.0
;
if
(
widget
.
navigationBar
is
CupertinoNavigationBar
)
{
final
CupertinoNavigationBar
top
=
widget
.
navigationBar
;
if
(
widget
.
navigationBar
!=
null
)
{
topPadding
+=
MediaQuery
.
of
(
context
).
padding
.
top
;
if
(
top
.
opaque
)
topPadding
+=
top
.
preferredSize
.
height
;
topPadding
+=
widget
.
navigationBar
.
preferredSize
.
height
;
}
double
bottomPadding
=
0.0
;
...
...
packages/flutter/test/cupertino/nav_bar_test.dart
View file @
8475e0b2
...
...
@@ -81,7 +81,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
const
CupertinoNavigationBar
(
leading:
const
_ExpectStyles
(
color:
const
Color
(
0xFF001122
),
index:
0x000001
),
middle:
const
_ExpectStyles
(
color:
const
Color
(
0xFF000000
),
index:
0x000100
),
middle:
const
_ExpectStyles
(
color:
const
Color
(
0xFF000000
),
letterSpacing:
-
0.72
,
index:
0x000100
),
trailing:
const
_ExpectStyles
(
color:
const
Color
(
0xFF001122
),
index:
0x010000
),
actionsForegroundColor:
const
Color
(
0xFF001122
),
);
...
...
@@ -129,9 +129,8 @@ void main() {
child:
new
CustomScrollView
(
controller:
scrollController
,
slivers:
<
Widget
>[
const
CupertinoNavigationBar
(
middle:
const
Text
(
'Title'
),
largeTitle:
true
,
const
CupertinoSliverNavigationBar
(
largeTitle:
const
Text
(
'Title'
),
),
new
SliverToBoxAdapter
(
child:
new
Container
(
...
...
@@ -204,12 +203,85 @@ void main() {
// The OverflowBox is squished with the text in it.
expect
(
tester
.
getSize
(
find
.
widgetWithText
(
OverflowBox
,
'Title'
)).
height
,
0.0
);
});
testWidgets
(
'Small title can be overriden'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
new
ScrollController
();
await
tester
.
pumpWidget
(
new
WidgetsApp
(
color:
const
Color
(
0xFFFFFFFF
),
onGenerateRoute:
(
RouteSettings
settings
)
{
return
new
CupertinoPageRoute
<
Null
>(
settings:
settings
,
builder:
(
BuildContext
context
)
{
return
new
CupertinoScaffold
(
child:
new
CustomScrollView
(
controller:
scrollController
,
slivers:
<
Widget
>[
const
CupertinoSliverNavigationBar
(
middle:
const
Text
(
'Different title'
),
largeTitle:
const
Text
(
'Title'
),
),
new
SliverToBoxAdapter
(
child:
new
Container
(
height:
1200.0
,
),
),
],
),
);
},
);
},
),
);
expect
(
scrollController
.
offset
,
0.0
);
expect
(
tester
.
getTopLeft
(
find
.
byType
(
NavigationToolbar
)).
dy
,
0.0
);
expect
(
tester
.
getSize
(
find
.
byType
(
NavigationToolbar
)).
height
,
44.0
);
expect
(
find
.
text
(
'Title'
),
findsOneWidget
);
expect
(
find
.
text
(
'Different title'
),
findsOneWidget
);
RenderOpacity
largeTitleOpacity
=
tester
.
element
(
find
.
text
(
'Title'
)).
ancestorRenderObjectOfType
(
const
TypeMatcher
<
RenderOpacity
>());
// Large title initially visible.
expect
(
largeTitleOpacity
.
opacity
,
1.0
);
// Middle widget not even wrapped with RenderOpacity, i.e. is always visible.
expect
(
tester
.
element
(
find
.
text
(
'Different title'
)).
ancestorRenderObjectOfType
(
const
TypeMatcher
<
RenderOpacity
>()),
isNull
,
);
expect
(
tester
.
getBottomLeft
(
find
.
text
(
'Title'
)).
dy
,
44.0
+
56.0
-
8.0
);
// Static part + extension - padding.
scrollController
.
jumpTo
(
600.0
);
await
tester
.
pump
();
// Once to trigger the opacity animation.
await
tester
.
pump
(
const
Duration
(
milliseconds:
300
));
largeTitleOpacity
=
tester
.
element
(
find
.
text
(
'Title'
)).
ancestorRenderObjectOfType
(
const
TypeMatcher
<
RenderOpacity
>());
// Large title no longer visible.
expect
(
largeTitleOpacity
.
opacity
,
0.0
);
// The persistent toolbar doesn't move or change size.
expect
(
tester
.
getTopLeft
(
find
.
byType
(
NavigationToolbar
)).
dy
,
0.0
);
expect
(
tester
.
getSize
(
find
.
byType
(
NavigationToolbar
)).
height
,
44.0
);
expect
(
tester
.
getBottomLeft
(
find
.
text
(
'Title'
)).
dy
,
44.0
-
8.0
);
// Extension gone, (static part - padding) left.
});
}
class
_ExpectStyles
extends
StatelessWidget
{
const
_ExpectStyles
({
this
.
color
,
this
.
index
});
const
_ExpectStyles
({
this
.
color
,
this
.
letterSpacing
,
this
.
index
});
final
Color
color
;
final
double
letterSpacing
;
final
int
index
;
@override
...
...
@@ -217,7 +289,7 @@ class _ExpectStyles extends StatelessWidget {
final
TextStyle
style
=
DefaultTextStyle
.
of
(
context
).
style
;
expect
(
style
.
color
,
color
);
expect
(
style
.
fontSize
,
17.0
);
expect
(
style
.
letterSpacing
,
-
0.24
);
expect
(
style
.
letterSpacing
,
letterSpacing
??
-
0.24
);
count
+=
index
;
return
new
Container
();
}
...
...
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