mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Merge pull request #1348 from abarth/focus_blur
Add the ability to lose focus
This commit is contained in:
commit
ed34622214
@ -90,6 +90,7 @@ class InputState extends ScrollableState<Input> {
|
||||
}
|
||||
|
||||
void _handleTextSubmitted() {
|
||||
Focus.clear(context);
|
||||
if (config.onSubmitted != null)
|
||||
config.onSubmitted(_value);
|
||||
}
|
||||
|
||||
@ -136,6 +136,7 @@ class EditableString implements KeyboardClient {
|
||||
}
|
||||
|
||||
void submit(SubmitAction action) {
|
||||
composing = const TextRange.empty();
|
||||
onSubmitted();
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ class _FocusScope extends InheritedWidget {
|
||||
Widget child
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
final FocusState focusState;
|
||||
final _FocusState focusState;
|
||||
final bool scopeFocused;
|
||||
|
||||
// These are mutable because we implicitly change them when they're null in
|
||||
@ -144,6 +144,12 @@ class Focus extends StatefulComponent {
|
||||
}
|
||||
}
|
||||
|
||||
static void clear(BuildContext context) {
|
||||
_FocusScope focusScope = context.ancestorWidgetOfExactType(_FocusScope);
|
||||
if (focusScope != null)
|
||||
focusScope.focusState._clearFocusedWidget();
|
||||
}
|
||||
|
||||
/// Focuses a particular focus scope, identified by its GlobalKey. The widget
|
||||
/// must be in the widget tree.
|
||||
///
|
||||
@ -157,10 +163,10 @@ class Focus extends StatefulComponent {
|
||||
focusScope.focusState._setFocusedScope(key);
|
||||
}
|
||||
|
||||
FocusState createState() => new FocusState();
|
||||
_FocusState createState() => new _FocusState();
|
||||
}
|
||||
|
||||
class FocusState extends State<Focus> {
|
||||
class _FocusState extends State<Focus> {
|
||||
GlobalKey _focusedWidget; // when null, the first component to ask if it's focused will get the focus
|
||||
GlobalKey _currentlyRegisteredWidgetRemovalListenerKey;
|
||||
|
||||
@ -181,12 +187,19 @@ class FocusState extends State<Focus> {
|
||||
}
|
||||
}
|
||||
|
||||
void _clearFocusedWidget() {
|
||||
if (_focusedWidget != null) {
|
||||
_updateWidgetRemovalListener(null);
|
||||
setState(() {
|
||||
_focusedWidget = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _handleWidgetRemoved(GlobalKey key) {
|
||||
assert(key != null);
|
||||
assert(_focusedWidget == key);
|
||||
_updateWidgetRemovalListener(null);
|
||||
setState(() {
|
||||
_focusedWidget = null;
|
||||
});
|
||||
_clearFocusedWidget();
|
||||
}
|
||||
|
||||
void _updateWidgetRemovalListener(GlobalKey key) {
|
||||
|
||||
@ -7,11 +7,19 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
class TestFocusable extends StatelessComponent {
|
||||
TestFocusable(this.no, this.yes, GlobalKey key) : super(key: key);
|
||||
TestFocusable({
|
||||
GlobalKey key,
|
||||
this.no,
|
||||
this.yes,
|
||||
this.autofocus: true
|
||||
}) : super(key: key);
|
||||
|
||||
final String no;
|
||||
final String yes;
|
||||
final bool autofocus;
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
bool focused = Focus.at(context, autofocus: true);
|
||||
bool focused = Focus.at(context, autofocus: autofocus);
|
||||
return new GestureDetector(
|
||||
onTap: () { Focus.moveTo(key); },
|
||||
child: new Text(focused ? yes : no)
|
||||
@ -29,8 +37,16 @@ void main() {
|
||||
child: new Column(
|
||||
children: <Widget>[
|
||||
// reverse these when you fix https://github.com/flutter/engine/issues/1495
|
||||
new TestFocusable('b', 'B FOCUSED', keyB),
|
||||
new TestFocusable('a', 'A FOCUSED', keyA),
|
||||
new TestFocusable(
|
||||
key: keyB,
|
||||
no: 'b',
|
||||
yes: 'B FOCUSED'
|
||||
),
|
||||
new TestFocusable(
|
||||
key: keyA,
|
||||
no: 'a',
|
||||
yes: 'A FOCUSED'
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
@ -65,4 +81,35 @@ void main() {
|
||||
expect(tester.findText('B FOCUSED'), isNull);
|
||||
});
|
||||
});
|
||||
|
||||
test('Can blur', () {
|
||||
testWidgets((WidgetTester tester) {
|
||||
GlobalKey keyA = new GlobalKey();
|
||||
tester.pumpWidget(
|
||||
new Focus(
|
||||
child: 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.clear(keyA.currentContext);
|
||||
tester.pump();
|
||||
|
||||
expect(tester.findText('a'), isNotNull);
|
||||
expect(tester.findText('A FOCUSED'), isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user