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
5cfccb91
Commit
5cfccb91
authored
Jan 27, 2016
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1397 from abarth/route_focus
Keyboard doesn't dismiss when the drawer comes up
parents
594e7000
a5351643
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
138 additions
and
54 deletions
+138
-54
drawer.dart
packages/flutter/lib/src/material/drawer.dart
+4
-1
focus.dart
packages/flutter/lib/src/widgets/focus.dart
+30
-42
routes.dart
packages/flutter/lib/src/widgets/routes.dart
+15
-11
focus_test.dart
packages/flutter/test/widget/focus_test.dart
+89
-0
No files found.
packages/flutter/lib/src/material/drawer.dart
View file @
5cfccb91
...
...
@@ -81,6 +81,8 @@ class DrawerControllerState extends State<DrawerController> {
}
LocalHistoryEntry
_historyEntry
;
// TODO(abarth): This should be a GlobalValueKey when those exist.
GlobalKey
get
_focusKey
=>
new
GlobalObjectKey
(
config
.
key
);
void
_ensureHistoryEntry
()
{
if
(
_historyEntry
==
null
)
{
...
...
@@ -88,6 +90,7 @@ class DrawerControllerState extends State<DrawerController> {
if
(
route
!=
null
)
{
_historyEntry
=
new
LocalHistoryEntry
(
onRemove:
_handleHistoryEntryRemoved
);
route
.
addLocalHistoryEntry
(
_historyEntry
);
Focus
.
moveScopeTo
(
_focusKey
,
context:
context
);
}
}
}
...
...
@@ -194,7 +197,7 @@ class DrawerControllerState extends State<DrawerController> {
onSizeChanged:
_handleSizeChanged
,
child:
new
RepaintBoundary
(
child:
new
Focus
(
key:
new
GlobalObjectKey
(
config
.
key
)
,
key:
_focusKey
,
child:
config
.
child
)
)
...
...
packages/flutter/lib/src/widgets/focus.dart
View file @
5cfccb91
...
...
@@ -34,9 +34,9 @@ class _FocusScope extends InheritedWidget {
GlobalKey
focusedScope
;
GlobalKey
focusedWidget
;
// The
...IfUnset() methods don't need to notify descendants because by
//
definition they are only going to make a change the very first time tha
t
// our state is checked.
// The
_setFocusedWidgetIfUnset() methodsdon't need to notify descendants
//
because by definition they are only going to make a change the very firs
t
//
time that
our state is checked.
void
_setFocusedWidgetIfUnset
(
GlobalKey
key
)
{
focusState
.
_setFocusedWidgetIfUnset
(
key
);
...
...
@@ -44,12 +44,6 @@ class _FocusScope extends InheritedWidget {
focusedScope
=
focusState
.
_focusedScope
==
_noFocusedScope
?
null
:
focusState
.
_focusedScope
;
}
void
_setFocusedScopeIfUnset
(
GlobalKey
key
)
{
focusState
.
_setFocusedScopeIfUnset
(
key
);
assert
(
focusedWidget
==
focusState
.
_focusedWidget
);
focusedScope
=
focusState
.
_focusedScope
==
_noFocusedScope
?
null
:
focusState
.
_focusedScope
;
}
bool
updateShouldNotify
(
_FocusScope
oldWidget
)
{
if
(
scopeFocused
!=
oldWidget
.
scopeFocused
)
return
true
;
...
...
@@ -77,14 +71,12 @@ class _FocusScope extends InheritedWidget {
class
Focus
extends
StatefulComponent
{
Focus
({
GlobalKey
key
,
// key is required if this is a nested Focus scope
this
.
autofocus
:
false
,
GlobalKey
key
,
this
.
child
})
:
super
(
key:
key
)
{
assert
(
!
autofocus
||
key
!=
null
);
assert
(
key
!=
null
);
}
final
bool
autofocus
;
final
Widget
child
;
static
GlobalKey
debugOnlyFocusedKey
;
...
...
@@ -114,15 +106,13 @@ class Focus extends StatefulComponent {
return
true
;
}
static
bool
_atScope
(
BuildContext
context
,
{
bool
autofocus:
false
}
)
{
static
bool
_atScope
(
BuildContext
context
)
{
assert
(
context
!=
null
);
assert
(
context
.
widget
!=
null
);
assert
(
context
.
widget
is
Focus
);
assert
(
context
.
widget
.
key
!=
null
);
_FocusScope
focusScope
=
context
.
inheritFromWidgetOfExactType
(
_FocusScope
);
if
(
focusScope
!=
null
)
{
assert
(
context
.
widget
.
key
!=
null
);
if
(
autofocus
)
focusScope
.
_setFocusedScopeIfUnset
(
context
.
widget
.
key
);
return
focusScope
.
scopeFocused
&&
focusScope
.
focusedScope
==
context
.
widget
.
key
;
}
...
...
@@ -150,15 +140,20 @@ class Focus extends StatefulComponent {
focusScope
.
focusState
.
_clearFocusedWidget
();
}
/// Focuses a particular focus scope, identified by its GlobalKey. The widget
/// must be in the widget tree.
/// Focuses a particular focus scope, identified by its GlobalKey.
///
/// Don't call moveScopeTo() from your build() functions, it's intended to be
/// called from event listeners, e.g. in response to a finger tap or tab key.
static
void
moveScopeTo
(
GlobalKey
key
)
{
assert
(
key
.
currentWidget
is
Focus
);
assert
(
key
.
currentContext
!=
null
);
_FocusScope
focusScope
=
key
.
currentContext
.
ancestorWidgetOfExactType
(
_FocusScope
);
static
void
moveScopeTo
(
GlobalKey
key
,
{
BuildContext
context
})
{
_FocusScope
focusScope
;
BuildContext
searchContext
=
key
.
currentContext
;
if
(
searchContext
!=
null
)
{
assert
(
key
.
currentWidget
is
Focus
);
focusScope
=
searchContext
.
ancestorWidgetOfExactType
(
_FocusScope
);
assert
(
context
==
null
||
focusScope
==
context
.
ancestorWidgetOfExactType
(
_FocusScope
));
}
else
{
focusScope
=
context
.
ancestorWidgetOfExactType
(
_FocusScope
);
}
if
(
focusScope
!=
null
)
focusScope
.
focusState
.
_setFocusedScope
(
key
);
}
...
...
@@ -167,6 +162,18 @@ class Focus extends StatefulComponent {
}
class
_FocusState
extends
State
<
Focus
>
{
void
initState
()
{
super
.
initState
();
_updateWidgetRemovalListener
(
_focusedWidget
);
_updateScopeRemovalListener
(
_focusedScope
);
}
void
dispose
()
{
_updateWidgetRemovalListener
(
null
);
_updateScopeRemovalListener
(
null
);
super
.
dispose
();
}
GlobalKey
_focusedWidget
;
// when null, the first component to ask if it's focused will get the focus
GlobalKey
_currentlyRegisteredWidgetRemovalListenerKey
;
...
...
@@ -222,13 +229,6 @@ class _FocusState extends State<Focus> {
_updateScopeRemovalListener
(
key
);
}
void
_setFocusedScopeIfUnset
(
GlobalKey
key
)
{
if
(
_focusedScope
==
null
)
{
_focusedScope
=
key
;
_updateScopeRemovalListener
(
key
);
}
}
void
_scopeRemoved
(
GlobalKey
key
)
{
assert
(
_focusedScope
==
key
);
GlobalKey
.
unregisterRemoveListener
(
_currentlyRegisteredScopeRemovalListenerKey
,
_scopeRemoved
);
...
...
@@ -248,18 +248,6 @@ class _FocusState extends State<Focus> {
}
}
void
initState
()
{
super
.
initState
();
_updateWidgetRemovalListener
(
_focusedWidget
);
_updateScopeRemovalListener
(
_focusedScope
);
}
void
dispose
()
{
_updateWidgetRemovalListener
(
null
);
_updateScopeRemovalListener
(
null
);
super
.
dispose
();
}
Size
_mediaSize
;
EdgeDims
_mediaPadding
;
...
...
packages/flutter/lib/src/widgets/routes.dart
View file @
5cfccb91
...
...
@@ -339,20 +339,20 @@ class _ModalScopeState extends State<_ModalScope> {
if
(
config
.
route
.
offstage
)
{
contents
=
new
OffStage
(
child:
contents
);
}
else
{
contents
=
new
Focus
(
key:
new
GlobalObjectKey
(
config
.
route
),
child:
new
IgnorePointer
(
ignoring:
config
.
route
.
animation
?.
status
==
AnimationStatus
.
reverse
,
child:
config
.
route
.
buildTransitions
(
context
,
config
.
route
.
animation
,
config
.
route
.
forwardAnimation
,
contents
)
contents
=
new
IgnorePointer
(
ignoring:
config
.
route
.
animation
?.
status
==
AnimationStatus
.
reverse
,
child:
config
.
route
.
buildTransitions
(
context
,
config
.
route
.
animation
,
config
.
route
.
forwardAnimation
,
contents
)
);
}
contents
=
new
RepaintBoundary
(
child:
contents
);
contents
=
new
Focus
(
key:
new
GlobalObjectKey
(
config
.
route
),
child:
new
RepaintBoundary
(
child:
contents
)
);
ModalPosition
position
=
config
.
route
.
getPosition
(
context
);
if
(
position
==
null
)
return
contents
;
...
...
@@ -401,6 +401,10 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
return
child
;
}
void
didPush
()
{
Focus
.
moveScopeTo
(
new
GlobalObjectKey
(
this
),
context:
navigator
.
context
);
super
.
didPush
();
}
// The API for subclasses to override - used by this class
...
...
packages/flutter/test/widget/focus_test.dart
View file @
5cfccb91
...
...
@@ -30,10 +30,12 @@ class TestFocusable extends StatelessComponent {
void
main
(
)
{
test
(
'Can have multiple focused children and they update accordingly'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
GlobalKey
keyFocus
=
new
GlobalKey
();
GlobalKey
keyA
=
new
GlobalKey
();
GlobalKey
keyB
=
new
GlobalKey
();
tester
.
pumpWidget
(
new
Focus
(
key:
keyFocus
,
child:
new
Column
(
children:
<
Widget
>[
// reverse these when you fix https://github.com/flutter/engine/issues/1495
...
...
@@ -84,9 +86,11 @@ void main() {
test
(
'Can blur'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
GlobalKey
keyFocus
=
new
GlobalKey
();
GlobalKey
keyA
=
new
GlobalKey
();
tester
.
pumpWidget
(
new
Focus
(
key:
keyFocus
,
child:
new
TestFocusable
(
key:
keyA
,
no:
'a'
,
...
...
@@ -112,4 +116,89 @@ void main() {
expect
(
tester
.
findText
(
'A FOCUSED'
),
isNull
);
});
});
test
(
'Can move focus to scope'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
GlobalKey
keyParentFocus
=
new
GlobalKey
();
GlobalKey
keyChildFocus
=
new
GlobalKey
();
GlobalKey
keyA
=
new
GlobalKey
();
tester
.
pumpWidget
(
new
Focus
(
key:
keyParentFocus
,
child:
new
Row
(
children:
[
new
TestFocusable
(
key:
keyA
,
no:
'a'
,
yes:
'A FOCUSED'
,
autofocus:
false
)
]
)
)
);
expect
(
tester
.
findText
(
'a'
),
isNotNull
);
expect
(
tester
.
findText
(
'A FOCUSED'
),
isNull
);
Focus
.
moveTo
(
keyA
);
tester
.
pump
();
expect
(
tester
.
findText
(
'a'
),
isNull
);
expect
(
tester
.
findText
(
'A FOCUSED'
),
isNotNull
);
Focus
.
moveScopeTo
(
keyChildFocus
,
context:
keyA
.
currentContext
);
tester
.
pumpWidget
(
new
Focus
(
key:
keyParentFocus
,
child:
new
Row
(
children:
[
new
TestFocusable
(
key:
keyA
,
no:
'a'
,
yes:
'A FOCUSED'
,
autofocus:
false
),
new
Focus
(
key:
keyChildFocus
,
child:
new
Container
(
width:
50.0
,
height:
50.0
)
)
]
)
)
);
expect
(
tester
.
findText
(
'a'
),
isNotNull
);
expect
(
tester
.
findText
(
'A FOCUSED'
),
isNull
);
tester
.
pumpWidget
(
new
Focus
(
key:
keyParentFocus
,
child:
new
Row
(
children:
[
new
TestFocusable
(
key:
keyA
,
no:
'a'
,
yes:
'A FOCUSED'
,
autofocus:
false
)
]
)
)
);
// Focus has received the removal notification but we haven't rebuilt yet.
expect
(
tester
.
findText
(
'a'
),
isNotNull
);
expect
(
tester
.
findText
(
'A FOCUSED'
),
isNull
);
tester
.
pump
();
expect
(
tester
.
findText
(
'a'
),
isNull
);
expect
(
tester
.
findText
(
'A FOCUSED'
),
isNotNull
);
});
});
}
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