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
f6a49913
Unverified
Commit
f6a49913
authored
Jan 08, 2021
by
Shi-Hao Hong
Committed by
GitHub
Jan 08, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[State Restoration] Scaffold.drawer and Scaffold.endDrawer (#72788)
parent
5d1306e7
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
229 additions
and
11 deletions
+229
-11
drawer.dart
packages/flutter/lib/src/material/drawer.dart
+25
-1
scaffold.dart
packages/flutter/lib/src/material/scaffold.dart
+35
-10
drawer_test.dart
packages/flutter/test/material/drawer_test.dart
+169
-0
No files found.
packages/flutter/lib/src/material/drawer.dart
View file @
f6a49913
...
...
@@ -231,6 +231,7 @@ class DrawerController extends StatefulWidget {
GlobalKey
?
key
,
required
this
.
child
,
required
this
.
alignment
,
this
.
isDrawerOpen
=
false
,
this
.
drawerCallback
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
scrimColor
,
...
...
@@ -298,6 +299,14 @@ class DrawerController extends StatefulWidget {
/// 20.0 will be added to `MediaQuery.of(context).padding.left`.
final
double
?
edgeDragWidth
;
/// Whether or not the drawer is opened or closed.
///
/// This parameter is primarily used by the state restoration framework
/// to restore the drawer's animation controller to the open or closed state
/// depending on what was last saved to the target platform before the
/// application was killed.
final
bool
isDrawerOpen
;
@override
DrawerControllerState
createState
()
=>
DrawerControllerState
();
}
...
...
@@ -310,7 +319,12 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
void
initState
()
{
super
.
initState
();
_scrimColorTween
=
_buildScrimColorTween
();
_controller
=
AnimationController
(
duration:
_kBaseSettleDuration
,
vsync:
this
)
_controller
=
AnimationController
(
value:
widget
.
isDrawerOpen
?
1.0
:
0.0
,
duration:
_kBaseSettleDuration
,
vsync:
this
,
);
_controller
..
addListener
(
_animationChanged
)
..
addStatusListener
(
_animationStatusChanged
);
}
...
...
@@ -327,6 +341,16 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
super
.
didUpdateWidget
(
oldWidget
);
if
(
widget
.
scrimColor
!=
oldWidget
.
scrimColor
)
_scrimColorTween
=
_buildScrimColorTween
();
if
(
widget
.
isDrawerOpen
!=
oldWidget
.
isDrawerOpen
)
{
switch
(
_controller
.
status
)
{
case
AnimationStatus
.
completed
:
case
AnimationStatus
.
dismissed
:
_controller
.
value
=
widget
.
isDrawerOpen
?
1.0
:
0.0
;
break
;
default
:
break
;
}
}
}
void
_animationChanged
()
{
...
...
packages/flutter/lib/src/material/scaffold.dart
View file @
f6a49913
...
...
@@ -1459,6 +1459,7 @@ class Scaffold extends StatefulWidget {
this
.
drawerEdgeDragWidth
,
this
.
drawerEnableOpenDragGesture
=
true
,
this
.
endDrawerEnableOpenDragGesture
=
true
,
this
.
restorationId
,
})
:
assert
(
primary
!=
null
),
assert
(
extendBody
!=
null
),
assert
(
extendBodyBehindAppBar
!=
null
),
...
...
@@ -1783,6 +1784,20 @@ class Scaffold extends StatefulWidget {
/// By default, the drag gesture is enabled.
final
bool
endDrawerEnableOpenDragGesture
;
/// Restoration ID to save and restore the state of the [Scaffold].
///
/// If it is non-null, the scaffold will persist and restore whether the
/// [drawer] and [endDrawer] was open or closed.
///
/// The state of this widget is persisted in a [RestorationBucket] claimed
/// from the surrounding [RestorationScope] using the provided restoration ID.
///
/// See also:
///
/// * [RestorationManager], which explains how state restoration works in
/// Flutter.
final
String
?
restorationId
;
/// Finds the [ScaffoldState] from the closest instance of this class that
/// encloses the given context.
///
...
...
@@ -2055,7 +2070,15 @@ class Scaffold extends StatefulWidget {
///
/// Can display [BottomSheet]s. Retrieve a [ScaffoldState] from the current
/// [BuildContext] using [Scaffold.of].
class
ScaffoldState
extends
State
<
Scaffold
>
with
TickerProviderStateMixin
{
class
ScaffoldState
extends
State
<
Scaffold
>
with
TickerProviderStateMixin
,
RestorationMixin
{
@override
String
?
get
restorationId
=>
widget
.
restorationId
;
@override
void
restoreState
(
RestorationBucket
?
oldBucket
,
bool
initialRestore
)
{
registerForRestoration
(
_drawerOpened
,
'drawer_open'
);
registerForRestoration
(
_endDrawerOpened
,
'end_drawer_open'
);
}
// DRAWER API
...
...
@@ -2076,8 +2099,8 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
///
/// This is based on the appBar preferred height plus the top padding.
double
?
get
appBarMaxHeight
=>
_appBarMaxHeight
;
bool
_drawerOpened
=
false
;
bool
_endDrawerOpened
=
false
;
final
RestorableBool
_drawerOpened
=
RestorableBool
(
false
)
;
final
RestorableBool
_endDrawerOpened
=
RestorableBool
(
false
)
;
/// Whether the [Scaffold.drawer] is opened.
///
...
...
@@ -2085,7 +2108,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
///
/// * [ScaffoldState.openDrawer], which opens the [Scaffold.drawer] of a
/// [Scaffold].
bool
get
isDrawerOpen
=>
_drawerOpened
;
bool
get
isDrawerOpen
=>
_drawerOpened
.
value
;
/// Whether the [Scaffold.endDrawer] is opened.
///
...
...
@@ -2093,18 +2116,18 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
///
/// * [ScaffoldState.openEndDrawer], which opens the [Scaffold.endDrawer] of
/// a [Scaffold].
bool
get
isEndDrawerOpen
=>
_endDrawerOpened
;
bool
get
isEndDrawerOpen
=>
_endDrawerOpened
.
value
;
void
_drawerOpenedCallback
(
bool
isOpened
)
{
setState
(()
{
_drawerOpened
=
isOpened
;
_drawerOpened
.
value
=
isOpened
;
});
widget
.
onDrawerChanged
?.
call
(
isOpened
);
}
void
_endDrawerOpenedCallback
(
bool
isOpened
)
{
setState
(()
{
_endDrawerOpened
=
isOpened
;
_endDrawerOpened
.
value
=
isOpened
;
});
widget
.
onEndDrawerChanged
?.
call
(
isOpened
);
}
...
...
@@ -2122,7 +2145,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
///
/// See [Scaffold.of] for information about how to obtain the [ScaffoldState].
void
openDrawer
()
{
if
(
_endDrawerKey
.
currentState
!=
null
&&
_endDrawerOpened
)
if
(
_endDrawerKey
.
currentState
!=
null
&&
_endDrawerOpened
.
value
)
_endDrawerKey
.
currentState
!.
close
();
_drawerKey
.
currentState
?.
open
();
}
...
...
@@ -2140,7 +2163,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
///
/// See [Scaffold.of] for information about how to obtain the [ScaffoldState].
void
openEndDrawer
()
{
if
(
_drawerKey
.
currentState
!=
null
&&
_drawerOpened
)
if
(
_drawerKey
.
currentState
!=
null
&&
_drawerOpened
.
value
)
_drawerKey
.
currentState
!.
close
();
_endDrawerKey
.
currentState
?.
open
();
}
...
...
@@ -2859,6 +2882,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
scrimColor:
widget
.
drawerScrimColor
,
edgeDragWidth:
widget
.
drawerEdgeDragWidth
,
enableOpenDragGesture:
widget
.
endDrawerEnableOpenDragGesture
,
isDrawerOpen:
_endDrawerOpened
.
value
,
),
_ScaffoldSlot
.
endDrawer
,
// remove the side padding from the side we're not touching
...
...
@@ -2884,6 +2908,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
scrimColor:
widget
.
drawerScrimColor
,
edgeDragWidth:
widget
.
drawerEdgeDragWidth
,
enableOpenDragGesture:
widget
.
drawerEnableOpenDragGesture
,
isDrawerOpen:
_drawerOpened
.
value
,
),
_ScaffoldSlot
.
drawer
,
// remove the side padding from the side we're not touching
...
...
@@ -3145,7 +3170,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
break
;
}
if
(
_endDrawerOpened
)
{
if
(
_endDrawerOpened
.
value
)
{
_buildDrawer
(
children
,
textDirection
);
_buildEndDrawer
(
children
,
textDirection
);
}
else
{
...
...
packages/flutter/test/material/drawer_test.dart
View file @
f6a49913
...
...
@@ -215,4 +215,173 @@ void main() {
expect
(
state
.
isDrawerOpen
,
equals
(
false
));
expect
(
state
.
isEndDrawerOpen
,
equals
(
false
));
});
testWidgets
(
'Scaffold.drawer - null restorationId '
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
ScaffoldState
>
scaffoldKey
=
GlobalKey
<
ScaffoldState
>();
await
tester
.
pumpWidget
(
MaterialApp
(
restorationScopeId:
'app'
,
home:
Scaffold
(
key:
scaffoldKey
,
drawer:
const
Text
(
'drawer'
),
body:
Container
(),
),
),
);
await
tester
.
pump
();
// no effect
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
scaffoldKey
.
currentState
!.
openDrawer
();
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'drawer'
),
findsOneWidget
);
await
tester
.
restartAndRestore
();
// Drawer state should not have been saved.
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
});
testWidgets
(
'Scaffold.endDrawer - null restorationId '
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
ScaffoldState
>
scaffoldKey
=
GlobalKey
<
ScaffoldState
>();
await
tester
.
pumpWidget
(
MaterialApp
(
restorationScopeId:
'app'
,
home:
Scaffold
(
key:
scaffoldKey
,
drawer:
const
Text
(
'endDrawer'
),
body:
Container
(),
),
),
);
await
tester
.
pump
();
// no effect
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
scaffoldKey
.
currentState
!.
openDrawer
();
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'endDrawer'
),
findsOneWidget
);
await
tester
.
restartAndRestore
();
// Drawer state should not have been saved.
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
});
testWidgets
(
'Scaffold.drawer state restoration test'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
ScaffoldState
>
scaffoldKey
=
GlobalKey
<
ScaffoldState
>();
await
tester
.
pumpWidget
(
MaterialApp
(
restorationScopeId:
'app'
,
home:
Scaffold
(
key:
scaffoldKey
,
restorationId:
'scaffold'
,
drawer:
const
Text
(
'drawer'
),
body:
Container
(),
),
),
);
await
tester
.
pump
();
// no effect
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
scaffoldKey
.
currentState
!.
openDrawer
();
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'drawer'
),
findsOneWidget
);
await
tester
.
restartAndRestore
();
expect
(
find
.
text
(
'drawer'
),
findsOneWidget
);
final
TestRestorationData
data
=
await
tester
.
getRestorationData
();
await
tester
.
tapAt
(
const
Offset
(
750.0
,
100.0
));
// on the mask
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
await
tester
.
restoreFrom
(
data
);
expect
(
find
.
text
(
'drawer'
),
findsOneWidget
);
});
testWidgets
(
'Scaffold.endDrawer state restoration test'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
ScaffoldState
>
scaffoldKey
=
GlobalKey
<
ScaffoldState
>();
await
tester
.
pumpWidget
(
MaterialApp
(
restorationScopeId:
'app'
,
home:
Scaffold
(
key:
scaffoldKey
,
restorationId:
'scaffold'
,
endDrawer:
const
Text
(
'endDrawer'
),
body:
Container
(),
),
),
);
await
tester
.
pump
();
// no effect
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
scaffoldKey
.
currentState
!.
openEndDrawer
();
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'endDrawer'
),
findsOneWidget
);
await
tester
.
restartAndRestore
();
expect
(
find
.
text
(
'endDrawer'
),
findsOneWidget
);
final
TestRestorationData
data
=
await
tester
.
getRestorationData
();
await
tester
.
tapAt
(
const
Offset
(
750.0
,
100.0
));
// on the mask
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
await
tester
.
restoreFrom
(
data
);
expect
(
find
.
text
(
'endDrawer'
),
findsOneWidget
);
});
testWidgets
(
'Both drawer and endDrawer state restoration test'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
ScaffoldState
>
scaffoldKey
=
GlobalKey
<
ScaffoldState
>();
await
tester
.
pumpWidget
(
MaterialApp
(
restorationScopeId:
'app'
,
home:
Scaffold
(
restorationId:
'scaffold'
,
key:
scaffoldKey
,
drawer:
const
Text
(
'drawer'
),
endDrawer:
const
Text
(
'endDrawer'
),
body:
Container
(),
),
),
);
await
tester
.
pump
();
// no effect
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
scaffoldKey
.
currentState
!.
openDrawer
();
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'drawer'
),
findsOneWidget
);
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
await
tester
.
restartAndRestore
();
expect
(
find
.
text
(
'drawer'
),
findsOneWidget
);
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
TestRestorationData
data
=
await
tester
.
getRestorationData
();
await
tester
.
tapAt
(
const
Offset
(
750.0
,
100.0
));
// on the mask
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
await
tester
.
restoreFrom
(
data
);
expect
(
find
.
text
(
'drawer'
),
findsOneWidget
);
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
await
tester
.
tapAt
(
const
Offset
(
750.0
,
100.0
));
// on the mask
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
scaffoldKey
.
currentState
!.
openEndDrawer
();
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
expect
(
find
.
text
(
'endDrawer'
),
findsOneWidget
);
await
tester
.
restartAndRestore
();
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
expect
(
find
.
text
(
'endDrawer'
),
findsOneWidget
);
data
=
await
tester
.
getRestorationData
();
await
tester
.
tapAt
(
const
Offset
(
750.0
,
100.0
));
// on the mask
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
expect
(
find
.
text
(
'endDrawer'
),
findsNothing
);
await
tester
.
restoreFrom
(
data
);
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
expect
(
find
.
text
(
'endDrawer'
),
findsOneWidget
);
});
}
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