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
19f79ac8
Unverified
Commit
19f79ac8
authored
6 years ago
by
Hans Muller
Committed by
GitHub
6 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add extendBody parameter to Scaffold, body MediaQuery reflects BAB height (#27973)
parent
c8c67b79
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
166 additions
and
5 deletions
+166
-5
AUTHORS
AUTHORS
+1
-0
scaffold.dart
packages/flutter/lib/src/material/scaffold.dart
+107
-4
box.dart
packages/flutter/lib/src/rendering/box.dart
+1
-1
scaffold_test.dart
packages/flutter/test/material/scaffold_test.dart
+57
-0
No files found.
AUTHORS
View file @
19f79ac8
...
@@ -37,3 +37,4 @@ Sander Dalby Larsen <srdlarsen@gmail.com>
...
@@ -37,3 +37,4 @@ Sander Dalby Larsen <srdlarsen@gmail.com>
Marco Scannadinari <m@scannadinari.co.uk>
Marco Scannadinari <m@scannadinari.co.uk>
Frederik Schweiger <mail@flschweiger.net>
Frederik Schweiger <mail@flschweiger.net>
Martin Staadecker <machstg@gmail.com>
Martin Staadecker <machstg@gmail.com>
Igor Katsuba <katsuba.igor@gmail.com>
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/material/scaffold.dart
View file @
19f79ac8
...
@@ -275,6 +275,76 @@ class _ScaffoldGeometryNotifier extends ChangeNotifier implements ValueListenabl
...
@@ -275,6 +275,76 @@ class _ScaffoldGeometryNotifier extends ChangeNotifier implements ValueListenabl
}
}
}
}
// Used to communicate the height of the Scaffold's bottomNavigationBar and
// persistentFooterButtons to the LayoutBuilder which builds the Scaffold's body.
//
// Scaffold expects a _BodyBoxConstraints to be passed to the _BodyBuilder
// widget's LayoutBuilder, see _ScaffoldLayout.performLayout(). The BoxConstraints
// methods that construct new BoxConstraints objects, like copyWith() have not
// been overridden here because we expect the _BodyBoxConstraintsObject to be
// passed along unmodified to the LayoutBuilder. If that changes in the future
// then _BodyBuilder will assert.
class
_BodyBoxConstraints
extends
BoxConstraints
{
const
_BodyBoxConstraints
({
double
minWidth
=
0.0
,
double
maxWidth
=
double
.
infinity
,
double
minHeight
=
0.0
,
double
maxHeight
=
double
.
infinity
,
@required
this
.
bottomWidgetsHeight
,
})
:
assert
(
bottomWidgetsHeight
!=
null
),
assert
(
bottomWidgetsHeight
>=
0
),
super
(
minWidth:
minWidth
,
maxWidth:
maxWidth
,
minHeight:
minHeight
,
maxHeight:
maxHeight
);
final
double
bottomWidgetsHeight
;
// RenderObject.layout() will only short-circuit its call to its performLayout
// method if the new layout constraints are not == to the current constraints.
// If the height of the bottom widgets has changed, even though the constraints'
// min and max values have not, we still want performLayout to happen.
@override
bool
operator
==(
dynamic
other
)
{
if
(
super
!=
other
)
return
false
;
final
_BodyBoxConstraints
typedOther
=
other
;
return
bottomWidgetsHeight
==
typedOther
.
bottomWidgetsHeight
;
}
@override
int
get
hashCode
{
return
hashValues
(
super
.
hashCode
,
bottomWidgetsHeight
);
}
}
// Used when Scaffold.extendBody is true to wrap the scaffold's body in a MediaQuery
// whose padding accounts for the height of the bottomNavigationBar and/or the
// persistentFooterButtons.
//
// The bottom widgets' height is passed along via the _BodyBoxConstraints parameter.
// The constraints parameter is constructed in_ScaffoldLayout.performLayout().
class
_BodyBuilder
extends
StatelessWidget
{
const
_BodyBuilder
({
Key
key
,
this
.
body
})
:
super
(
key:
key
);
final
Widget
body
;
@override
Widget
build
(
BuildContext
context
)
{
return
LayoutBuilder
(
builder:
(
BuildContext
context
,
BoxConstraints
constraints
)
{
final
_BodyBoxConstraints
bodyConstraints
=
constraints
;
final
MediaQueryData
metrics
=
MediaQuery
.
of
(
context
);
return
MediaQuery
(
data:
metrics
.
copyWith
(
padding:
metrics
.
padding
.
copyWith
(
bottom:
math
.
max
(
metrics
.
padding
.
bottom
,
bodyConstraints
.
bottomWidgetsHeight
),
),
),
child:
body
,
);
},
);
}
}
class
_ScaffoldLayout
extends
MultiChildLayoutDelegate
{
class
_ScaffoldLayout
extends
MultiChildLayoutDelegate
{
_ScaffoldLayout
({
_ScaffoldLayout
({
@required
this
.
minInsets
,
@required
this
.
minInsets
,
...
@@ -285,12 +355,15 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
...
@@ -285,12 +355,15 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
@required
this
.
currentFloatingActionButtonLocation
,
@required
this
.
currentFloatingActionButtonLocation
,
@required
this
.
floatingActionButtonMoveAnimationProgress
,
@required
this
.
floatingActionButtonMoveAnimationProgress
,
@required
this
.
floatingActionButtonMotionAnimator
,
@required
this
.
floatingActionButtonMotionAnimator
,
@required
this
.
extendBody
,
})
:
assert
(
minInsets
!=
null
),
})
:
assert
(
minInsets
!=
null
),
assert
(
textDirection
!=
null
),
assert
(
textDirection
!=
null
),
assert
(
geometryNotifier
!=
null
),
assert
(
geometryNotifier
!=
null
),
assert
(
previousFloatingActionButtonLocation
!=
null
),
assert
(
previousFloatingActionButtonLocation
!=
null
),
assert
(
currentFloatingActionButtonLocation
!=
null
);
assert
(
currentFloatingActionButtonLocation
!=
null
),
assert
(
extendBody
!=
null
);
final
bool
extendBody
;
final
EdgeInsets
minInsets
;
final
EdgeInsets
minInsets
;
final
TextDirection
textDirection
;
final
TextDirection
textDirection
;
final
_ScaffoldGeometryNotifier
geometryNotifier
;
final
_ScaffoldGeometryNotifier
geometryNotifier
;
...
@@ -343,9 +416,17 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
...
@@ -343,9 +416,17 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
final
double
contentBottom
=
math
.
max
(
0.0
,
bottom
-
math
.
max
(
minInsets
.
bottom
,
bottomWidgetsHeight
));
final
double
contentBottom
=
math
.
max
(
0.0
,
bottom
-
math
.
max
(
minInsets
.
bottom
,
bottomWidgetsHeight
));
if
(
hasChild
(
_ScaffoldSlot
.
body
))
{
if
(
hasChild
(
_ScaffoldSlot
.
body
))
{
final
BoxConstraints
bodyConstraints
=
BoxConstraints
(
double
bodyMaxHeight
=
math
.
max
(
0.0
,
contentBottom
-
contentTop
);
if
(
extendBody
)
{
bodyMaxHeight
+=
bottomWidgetsHeight
;
assert
(
bodyMaxHeight
<=
math
.
max
(
0.0
,
looseConstraints
.
maxHeight
-
contentTop
));
}
final
BoxConstraints
bodyConstraints
=
_BodyBoxConstraints
(
maxWidth:
fullWidthConstraints
.
maxWidth
,
maxWidth:
fullWidthConstraints
.
maxWidth
,
maxHeight:
math
.
max
(
0.0
,
contentBottom
-
contentTop
),
maxHeight:
bodyMaxHeight
,
bottomWidgetsHeight:
extendBody
?
bottomWidgetsHeight
:
0.0
,
);
);
layoutChild
(
_ScaffoldSlot
.
body
,
bodyConstraints
);
layoutChild
(
_ScaffoldSlot
.
body
,
bodyConstraints
);
positionChild
(
_ScaffoldSlot
.
body
,
Offset
(
0.0
,
contentTop
));
positionChild
(
_ScaffoldSlot
.
body
,
Offset
(
0.0
,
contentTop
));
...
@@ -795,11 +876,29 @@ class Scaffold extends StatefulWidget {
...
@@ -795,11 +876,29 @@ class Scaffold extends StatefulWidget {
this
.
resizeToAvoidBottomPadding
,
this
.
resizeToAvoidBottomPadding
,
this
.
resizeToAvoidBottomInset
,
this
.
resizeToAvoidBottomInset
,
this
.
primary
=
true
,
this
.
primary
=
true
,
this
.
extendBody
=
false
,
this
.
drawerDragStartBehavior
=
DragStartBehavior
.
down
,
this
.
drawerDragStartBehavior
=
DragStartBehavior
.
down
,
})
:
assert
(
primary
!=
null
),
})
:
assert
(
primary
!=
null
),
assert
(
extendBody
!=
null
),
assert
(
drawerDragStartBehavior
!=
null
),
assert
(
drawerDragStartBehavior
!=
null
),
super
(
key:
key
);
super
(
key:
key
);
/// If true, and [bottomNavigationBar] or [persistentFooterButtons]
/// is specified, then the [body] extends to the bottom of the Scaffold,
/// instead of only extending to the top of the [bottomNavigationBar]
/// or the [persistentFooterButtons].
///
/// If true, a [MediaQuery] widget whose bottom padding matches the
/// the height of the [bottomNavigationBar] will be added above the
/// scaffold's [body].
///
/// This property is often useful when the [bottomNavigationBar] has
/// a non-rectangular shape, like [CircularNotchedRectangle], which
/// adds a [FloatingActionButton] sized notch to the top edge of the bar.
/// In this case specifying `extendBody: true` ensures that that scaffold's
/// body will be visible through the bottom navigation bar's notch.
final
bool
extendBody
;
/// An app bar to display at the top of the scaffold.
/// An app bar to display at the top of the scaffold.
final
PreferredSizeWidget
appBar
;
final
PreferredSizeWidget
appBar
;
...
@@ -1697,7 +1796,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
...
@@ -1697,7 +1796,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
_addIfNonNull
(
_addIfNonNull
(
children
,
children
,
widget
.
body
,
widget
.
body
!=
null
&&
widget
.
extendBody
?
_BodyBuilder
(
body:
widget
.
body
)
:
widget
.
body
,
_ScaffoldSlot
.
body
,
_ScaffoldSlot
.
body
,
removeLeftPadding:
false
,
removeLeftPadding:
false
,
removeTopPadding:
widget
.
appBar
!=
null
,
removeTopPadding:
widget
.
appBar
!=
null
,
...
@@ -1850,6 +1949,9 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
...
@@ -1850,6 +1949,9 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
bottom:
_resizeToAvoidBottomInset
?
mediaQuery
.
viewInsets
.
bottom
:
0.0
,
bottom:
_resizeToAvoidBottomInset
?
mediaQuery
.
viewInsets
.
bottom
:
0.0
,
);
);
// extendBody locked when keyboard is open
final
bool
_extendBody
=
minInsets
.
bottom
>
0
?
false
:
widget
.
extendBody
;
return
_ScaffoldScope
(
return
_ScaffoldScope
(
hasDrawer:
hasDrawer
,
hasDrawer:
hasDrawer
,
geometryNotifier:
_geometryNotifier
,
geometryNotifier:
_geometryNotifier
,
...
@@ -1861,6 +1963,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
...
@@ -1861,6 +1963,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
return
CustomMultiChildLayout
(
return
CustomMultiChildLayout
(
children:
children
,
children:
children
,
delegate:
_ScaffoldLayout
(
delegate:
_ScaffoldLayout
(
extendBody:
_extendBody
,
minInsets:
minInsets
,
minInsets:
minInsets
,
currentFloatingActionButtonLocation:
_floatingActionButtonLocation
,
currentFloatingActionButtonLocation:
_floatingActionButtonLocation
,
floatingActionButtonMoveAnimationProgress:
_floatingActionButtonMoveController
.
value
,
floatingActionButtonMoveAnimationProgress:
_floatingActionButtonMoveController
.
value
,
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/rendering/box.dart
View file @
19f79ac8
...
@@ -574,7 +574,7 @@ class BoxConstraints extends Constraints {
...
@@ -574,7 +574,7 @@ class BoxConstraints extends Constraints {
assert
(
debugAssertIsValid
());
assert
(
debugAssertIsValid
());
if
(
identical
(
this
,
other
))
if
(
identical
(
this
,
other
))
return
true
;
return
true
;
if
(
other
is
!
BoxConstraints
)
if
(
runtimeType
!=
other
.
runtimeType
)
return
false
;
return
false
;
final
BoxConstraints
typedOther
=
other
;
final
BoxConstraints
typedOther
=
other
;
assert
(
typedOther
.
debugAssertIsValid
());
assert
(
typedOther
.
debugAssertIsValid
());
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/material/scaffold_test.dart
View file @
19f79ac8
...
@@ -574,6 +574,63 @@ void main() {
...
@@ -574,6 +574,63 @@ void main() {
expect
(
tester
.
element
(
find
.
byKey
(
testKey
)).
size
,
const
Size
(
88.0
,
48.0
));
expect
(
tester
.
element
(
find
.
byKey
(
testKey
)).
size
,
const
Size
(
88.0
,
48.0
));
expect
(
tester
.
renderObject
<
RenderBox
>(
find
.
byKey
(
testKey
)).
localToGlobal
(
Offset
.
zero
),
const
Offset
(
0.0
,
0.0
));
expect
(
tester
.
renderObject
<
RenderBox
>(
find
.
byKey
(
testKey
)).
localToGlobal
(
Offset
.
zero
),
const
Offset
(
0.0
,
0.0
));
});
});
testWidgets
(
'body size with extendBody'
,
(
WidgetTester
tester
)
async
{
final
Key
bodyKey
=
UniqueKey
();
double
mediaQueryBottom
;
Widget
buildFrame
({
bool
extendBody
,
bool
resizeToAvoidBottomInset
,
double
viewInsetBottom
=
0.0
})
{
return
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
MediaQueryData
(
viewInsets:
EdgeInsets
.
only
(
bottom:
viewInsetBottom
),
),
child:
Scaffold
(
resizeToAvoidBottomInset:
resizeToAvoidBottomInset
,
extendBody:
extendBody
,
body:
Builder
(
builder:
(
BuildContext
context
)
{
mediaQueryBottom
=
MediaQuery
.
of
(
context
).
padding
.
bottom
;
return
Container
(
key:
bodyKey
);
},
),
bottomNavigationBar:
const
BottomAppBar
(
child:
SizedBox
(
height:
48.0
,),
),
),
),
);
}
await
tester
.
pumpWidget
(
buildFrame
(
extendBody:
true
));
expect
(
tester
.
getSize
(
find
.
byKey
(
bodyKey
)),
const
Size
(
800.0
,
600.0
));
expect
(
mediaQueryBottom
,
48.0
);
await
tester
.
pumpWidget
(
buildFrame
(
extendBody:
false
));
expect
(
tester
.
getSize
(
find
.
byKey
(
bodyKey
)),
const
Size
(
800.0
,
552.0
));
// 552 = 600 - 48 (BAB height)
expect
(
mediaQueryBottom
,
0.0
);
// If resizeToAvoidBottomInsets is false, same results as if it was unspecified (null).
await
tester
.
pumpWidget
(
buildFrame
(
extendBody:
true
,
resizeToAvoidBottomInset:
false
,
viewInsetBottom:
100.0
));
expect
(
tester
.
getSize
(
find
.
byKey
(
bodyKey
)),
const
Size
(
800.0
,
600.0
));
expect
(
mediaQueryBottom
,
48.0
);
await
tester
.
pumpWidget
(
buildFrame
(
extendBody:
false
,
resizeToAvoidBottomInset:
false
,
viewInsetBottom:
100.0
));
expect
(
tester
.
getSize
(
find
.
byKey
(
bodyKey
)),
const
Size
(
800.0
,
552.0
));
expect
(
mediaQueryBottom
,
0.0
);
// If resizeToAvoidBottomInsets is true and viewInsets.bottom is > the bottom
// navigation bar's height then the body always resizes and the MediaQuery
// isn't adjusted. This case corresponds to the keyboard appearing.
await
tester
.
pumpWidget
(
buildFrame
(
extendBody:
true
,
resizeToAvoidBottomInset:
true
,
viewInsetBottom:
100.0
));
expect
(
tester
.
getSize
(
find
.
byKey
(
bodyKey
)),
const
Size
(
800.0
,
500.0
));
expect
(
mediaQueryBottom
,
0.0
);
await
tester
.
pumpWidget
(
buildFrame
(
extendBody:
false
,
resizeToAvoidBottomInset:
true
,
viewInsetBottom:
100.0
));
expect
(
tester
.
getSize
(
find
.
byKey
(
bodyKey
)),
const
Size
(
800.0
,
500.0
));
expect
(
mediaQueryBottom
,
0.0
);
});
});
});
testWidgets
(
'Open drawer hides underlying semantics tree'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Open drawer hides underlying semantics tree'
,
(
WidgetTester
tester
)
async
{
...
...
This diff is collapsed.
Click to expand it.
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