diff --git a/packages/flutter/lib/src/material/input.dart b/packages/flutter/lib/src/material/input.dart
index c0cf1beef8f..89d095e4ab3 100644
--- a/packages/flutter/lib/src/material/input.dart
+++ b/packages/flutter/lib/src/material/input.dart
@@ -109,7 +109,7 @@ class _InputState extends State {
_editableString.selection.end);
} else if (!focused && _keyboardHandle.attached) {
_keyboardHandle.release();
- _editableString.composing = TextRange.empty;
+ _editableString.didDetachKeyboard();
}
}
diff --git a/packages/flutter/lib/src/services/keyboard.dart b/packages/flutter/lib/src/services/keyboard.dart
index f368c723128..8e82e3f0c51 100644
--- a/packages/flutter/lib/src/services/keyboard.dart
+++ b/packages/flutter/lib/src/services/keyboard.dart
@@ -23,8 +23,10 @@ class _KeyboardConnection {
static final _KeyboardConnection instance = new _KeyboardConnection();
}
+/// An interface to the system's keyboard.
+///
+/// Most clients will want to use the [keyboard] singleton instance.
class Keyboard {
-
Keyboard(this.service);
// The service is exposed in case you need direct access.
diff --git a/packages/flutter/lib/src/widgets/editable.dart b/packages/flutter/lib/src/widgets/editable.dart
index 945613f0395..dd573d5a0a3 100644
--- a/packages/flutter/lib/src/widgets/editable.dart
+++ b/packages/flutter/lib/src/widgets/editable.dart
@@ -26,11 +26,7 @@ class TextRange {
end = position;
/// A text range that contains nothing and is not in the text.
- const TextRange._empty()
- : start = -1,
- end = -1;
-
- static const TextRange empty = const TextRange._empty();
+ static const TextRange empty = const TextRange(start: -1, end: -1);
/// The index of the first character in the range.
final int start;
@@ -43,11 +39,29 @@ class TextRange {
/// Whether this range is empty (but still potentially placed inside the text).
bool get isCollapsed => start == end;
+
+ /// The text before this range.
+ String textBefore(String text) {
+ return text.substring(0, start);
+ }
+
+ /// The text after this range.
+ String textAfter(String text) {
+ return text.substring(end);
+ }
+
+ /// The text inside this range.
+ String textInside(String text) {
+ return text.substring(start, end);
+ }
}
-/// A string that can be manipulated by a keyboard.
-class EditableString implements KeyboardClient {
- EditableString({this.text: '', this.onUpdated, this.onSubmitted}) {
+class _KeyboardClientImpl implements KeyboardClient {
+ _KeyboardClientImpl({
+ this.text: '',
+ this.onUpdated,
+ this.onSubmitted
+ }) {
assert(onUpdated != null);
assert(onSubmitted != null);
stub = new KeyboardClientStub.unbound()..impl = this;
@@ -57,39 +71,24 @@ class EditableString implements KeyboardClient {
/// The current text being edited.
String text;
- // The range of text that is still being composed.
- TextRange composing = TextRange.empty;
-
- /// The range of text that is currently selected.
- TextRange selection;
-
/// Called whenever the text changes.
final VoidCallback onUpdated;
/// Called whenever the user indicates they are done editing the string.
final VoidCallback onSubmitted;
+ // The range of text that is still being composed.
+ TextRange composing = TextRange.empty;
+
+ /// The range of text that is currently selected.
+ TextRange selection = TextRange.empty;
+
/// A keyboard client stub that can be attached to a keyboard service.
KeyboardClientStub stub;
- /// The text before the given range.
- String textBefore(TextRange range) {
- return text.substring(0, range.start);
- }
-
- /// The text after the given range.
- String textAfter(TextRange range) {
- return text.substring(range.end);
- }
-
- /// The text inside the given range.
- String textInside(TextRange range) {
- return text.substring(range.start, range.end);
- }
-
void _delete(TextRange range) {
if (range.isCollapsed || !range.isValid) return;
- text = textBefore(range) + textAfter(range);
+ text = range.textBefore(text) + range.textAfter(text);
}
TextRange _append(String newText) {
@@ -101,8 +100,8 @@ class EditableString implements KeyboardClient {
TextRange _replace(TextRange range, String newText) {
assert(range.isValid);
- String before = textBefore(range);
- String after = textAfter(range);
+ String before = range.textBefore(text);
+ String after = range.textAfter(text);
text = before + newText + after;
return new TextRange(
@@ -168,6 +167,42 @@ class EditableString implements KeyboardClient {
}
}
+/// A string that can be manipulated by a keyboard.
+///
+/// Can be displayed with [RawEditableLine]. For a more featureful input widget,
+/// consider using [Input].
+class EditableString {
+ EditableString({
+ String text: '',
+ VoidCallback onUpdated,
+ VoidCallback onSubmitted
+ }) : _client = new _KeyboardClientImpl(
+ text: text,
+ onUpdated: onUpdated,
+ onSubmitted: onSubmitted
+ );
+
+ final _KeyboardClientImpl _client;
+
+ /// The current text being edited.
+ String get text => _client.text;
+
+ // The range of text that is still being composed.
+ TextRange get composing => _client.composing;
+
+ /// The range of text that is currently selected.
+ TextRange get selection => _client.selection;
+
+ /// A keyboard client stub that can be attached to a keyboard service.
+ ///
+ /// See [Keyboard].
+ KeyboardClientStub get stub => _client.stub;
+
+ void didDetachKeyboard() {
+ _client.composing = TextRange.empty;
+ }
+}
+
/// A basic single-line input control.
///
/// This control is not intended to be used directly. Instead, consider using
@@ -337,11 +372,11 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
);
return new StyledTextSpan(style, [
- new PlainTextSpan(value.textBefore(value.composing)),
+ new PlainTextSpan(value.composing.textBefore(value.text)),
new StyledTextSpan(composingStyle, [
- new PlainTextSpan(value.textInside(value.composing))
+ new PlainTextSpan(value.composing.textInside(value.text))
]),
- new PlainTextSpan(value.textAfter(value.composing))
+ new PlainTextSpan(value.composing.textAfter(value.text))
]);
}