Select all text inside TextField when it gets focus - flutter

On TextField foucus I want to select all text so that when the user starts typing the existing text gets deleted.
This will be alternative of : android:selectAllOnFocus="true" in Android.
How to achive this?

Pass a controller and focusNode explicitly, then you have full control:
final _controller = TextEditingController();
final _focusNode = FocusNode();
initState() {
super.initState();
_focusNode.addListener(() {
if(_focusNode.hasFocus) {
_controller.selection = TextSelection(baseOffset: 0, extentOffset: _controller.text.length);
}
});
}
build() => TextField(controller: _controller, focusNode: _focusNode);
Update
from https://github.com/flutter/flutter/issues/28307#issuecomment-467952074 to prevent endless loop:
_controller.addListener(() {
final newText = _controller.text.toLowerCase();
_controller.value = _controller.value.copyWith(
text: newText,
selection: TextSelection(baseOffset: newText.length, extentOffset: newText.length),
composing: TextRange.empty,
);
});

It's also possible to set the selection in onTap event. Like this:
TextField(
controller: _controller,
onTap: () => _controller.selection = TextSelection(baseOffset: 0, extentOffset: _controller.value.text.length),
)

It's actually much easier than the accepted answer.
First initialize a TextEditingController.
final _controller = TextEditingController();
Then, somewhere within your build method (probably within your edit text logic), set the text and the selection props like so.
_controller.text = textValue;
_controller.selection = TextSelection(
baseOffset: 0,
extentOffset: textValue.length,
);
In the TextFormField, make sure to assign the controller and set autofocus to true.
TextFormField(
controller: _controller,
autofocus: true,
//...more properties
That's it!

For a cleaner, reusable experience an Extension class method (see note below) is handy.
extension TextEditingControllerExt on TextEditingController {
void selectAll() {
if (text.isEmpty) return;
selection = TextSelection(baseOffset: 0, extentOffset: text.length);
}
}
On the field:
TextField(
controller: myController,
onTap: myController.selectAll
)
Example
On Dartpad:
https://dartpad.dev/?id=271737b109637f90a2fe5ea55ea2ac43
Note
In extension classes, this can be omitted.
text is assumed to be: this.text i.e. <this instance of controller>.text
Same with selection being actually this.selection.

As of Dart 2:
controller1.selection = TextSelection(baseOffset:0, extentOffset:controller1.text.length);

Related

How to set text using TextEditingController and placing the cursor at the end?

Minimal reproducible code:
final _controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: TextField(
controller: _controller,
keyboardType: TextInputType.number,
onChanged: (string) {
_controller.text = string; // Removing this works though!
_controller.selection = TextSelection.fromPosition(TextPosition(offset: _controller.text.length));
},
),
);
}
Problem:
As you can clearly see in the screenshot about the problem, typing 12 prints 21 and so on. You might ask what's the use of setting text in TextEditingController to the current string passed by onChanged, well, I need to format the current string but even the simplest string isn't able to set the text.
I think this can do the magic for you!
onChanged: (newText) {
var text = formatString(newText);
_controller.value = _controller.value.copyWith(
text: text,
selection: TextSelection.collapsed(offset: text.length),
);
}
Do your formatting like this and don't forget every time the newText is passed with already formatted value. (In this case, I replaced all commas to bring back my original string)
String formatString(String newText){
return newText.replaceAll(',', '').split('').join(',');
}
Interactive Example Reference: https://api.flutter.dev/flutter/widgets/TextEditingController-class.html#widgets.TextEditingController.1

ScrollView scrolls automatically if i set text to textfield using its controller

I have created a form using scrollview widget & when initState() method _getDataUser() is called i set some prefill controllerEmail.text to textfield which makes my scrollview to scroll to the TextFormField Email source code :
https://pastebin(dot)com/sFR7s4wS
I found a solution here, you can wrap your TextField into a Focus, and only when the user has focused on the text field we set showCursor to true.
bool showCursor = false;
Focus(
onFocusChange: (focus) => setState(() => showCursor = focus),
child: TextField(
showCursor: showCursor,
controller: _textController,
textCapitalization: TextCapitalization.words,
),
)
This is flutter's native functionality and I have programatically solved this using ScrollController and Future.delayed. Just assign your scroll view or list view to a scroll controller and do the following:
runZoned(() {
Future.delayed(Duration(seconds: 0), () {
_scrollController.jumpTo(0);
});
}, onError: (error, stackTrace) {
print('Zone Error: $error');
});

Flutter- TextEditingController listener get called multiple time for textfield

TextField controlled controller.addListener(() gets called multiple time after pressing the clear button, this will only happen if we are clearing it.
Snippet:
TextEditingController controller = new TextEditingController();
TextField field = new TextField(
controller: controller,
autofocus: true,
);
controller.addListener(() {
print("Pressed cancel button");
});
Video Link
Note: While adding characters in TextField listener method gets called only ones.
I guess that would be a defect on flutter, a possible solution would be to use onChanged()
TextField field = new TextField(
autofocus: true,
onChanged: (String value) {
print("Pressed clear button");
},
);
I have the same problem with Nexus 6p when used with API level 23 and Pixel with API 25.
but this problem did not occurs with Pixel with API28 and it does not occurs with Nexus6P with API26.
exact code from https://flutter.dev/docs/cookbook/forms/text-field-changes was used.
1. We need to create our own .clear() method
void clearField() {
print("c: clearField");
var newValue = textController.value.copyWith(
text: '',
selection: TextSelection.collapsed(offset: 0),
);
textController.value = newValue;
callApi('');
}
// and call it by :
child: TextField(
controller: textController,
autofocus: true,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(Icons.close),
onPressed: clearField, // call
),
),
),
2. We need to carefully handle changes
void changesOnField() {
print("c: changesOnField");
String text = textController.text;
if (text.isNotEmpty) { // set this
callApi(text);
}
}
Full Code
You may look into this repo and build it locally Github
Result

Add text to TextField from an outside source

I added a speech recognition to a text field, it works but I cannot manage to add the text to the textfield, is there a way to do that.
the textfield looks like this:
Widget _buildDescriptionTextField(productBloc) {
return StreamBuilder<Object>(
stream: productBloc.messageStream,
builder: (context, snapshot) {
return TextField(
maxLines: 3,
controller: _controllerMessage,
onChanged: productBloc.messageSink,
decoration: InputDecoration(
labelText: allTranslations.text(StringConstant.description),
errorText: snapshot.error,
suffixIcon: IconButton(icon: Icon(Icons.mic), onPressed: () {
if (_isAvailable && !_isListening)
_speechRecognition
.listen(locale: "en_US")
.then((result) => print('$result'));
},
),
),
);
}
);
}
I have a steam-builder to manage the added text manually, and an controller if this page is used for editing, then as suffixsIcon the iconButton to start the speech recognition. when I add the result text outside a text Widget it works but I need it inside the texField.
Just doing that should work no ?
setState(() => _controllerMessage.text = result)
You need to use TextEditingController properties. I assume you declared one as _controllerMessage.
To set new value to your TextField and keep the cursor in the end - use something similar to the example from the Docs.
e.g.
_speechRecognition
.listen(locale: "en_US")
.then(_onResult);
// ...
void _onResult(String result) {
setState(() {
_controllerMessage.value = _controllerMessage.value.copyWith(
text: result,
selection: TextSelection(baseOffset: result.length, extentOffset: result.length),
composing: TextRange.empty,
);
});
}
Let me know if this helped.
So What I did is just used the _speechRecognition.setRecognitionResultHandler from the documentation, to set a new value to the controller of the textField, like so:
_speechRecognition.setRecognitionResultHandler(
(String speech) => setState(() {
_controllerMessage = new TextEditingController(text: resultText = speech);
})
);
the textField stays like it was before, see question.

Style part of text in TextField

I'm implementing a custom text field and I would like to style certain keywords (namely hashtags) differently than the rest of the text as the user type them in.
Kind of like this:
Is there a way to do that in Flutter ?
This question is very similar to How to change color of particular text in a text field dynamically?
I answered it there in: https://stackoverflow.com/a/57846261/5280562
In short: you can extend EditableText widget including its EditableTextState class and override buildTextSpan method.
Below is a working example called AnnotatedEditableText that I use in my app.
You need to supply a list of Annotation objects which describe which ranges of text need to be highlighted and what style to use.
import 'package:flutter/widgets.dart';
class Annotation extends Comparable<Annotation> {
Annotation({#required this.range, this.style});
final TextRange range;
final TextStyle style;
#override
int compareTo(Annotation other) {
return range.start.compareTo(other.range.start);
}
#override
String toString() {
return 'Annotation(range:$range, style:$style)';
}
}
class AnnotatedEditableText extends EditableText {
AnnotatedEditableText({
Key key,
FocusNode focusNode,
TextEditingController controller,
TextStyle style,
ValueChanged<String> onChanged,
ValueChanged<String> onSubmitted,
Color cursorColor,
Color selectionColor,
TextSelectionControls selectionControls,
this.annotations,
}) : super(
key: key,
focusNode: focusNode,
controller: controller,
cursorColor: cursorColor,
style: style,
keyboardType: TextInputType.text,
autocorrect: true,
autofocus: true,
selectionColor: selectionColor,
selectionControls: selectionControls,
onChanged: onChanged,
onSubmitted: onSubmitted,
);
final List<Annotation> annotations;
#override
AnnotatedEditableTextState createState() => new AnnotatedEditableTextState();
}
class AnnotatedEditableTextState extends EditableTextState {
#override
AnnotatedEditableText get widget => super.widget;
List<Annotation> getRanges() {
var source = widget.annotations;
source.sort();
var result = new List<Annotation>();
Annotation prev;
for (var item in source) {
if (prev == null) {
// First item, check if we need one before it.
if (item.range.start > 0) {
result.add(new Annotation(
range: TextRange(start: 0, end: item.range.start),
));
}
result.add(item);
prev = item;
continue;
} else {
// Consequent item, check if there is a gap between.
if (prev.range.end > item.range.start) {
// Invalid ranges
throw new StateError(
'Invalid (intersecting) ranges for annotated field');
} else if (prev.range.end < item.range.start) {
result.add(Annotation(
range: TextRange(start: prev.range.end, end: item.range.start),
));
}
// Also add current annotation
result.add(item);
prev = item;
}
}
// Also check for trailing range
final String text = textEditingValue.text;
if (result.last.range.end < text.length) {
result.add(Annotation(
range: TextRange(start: result.last.range.end, end: text.length),
));
}
return result;
}
#override
TextSpan buildTextSpan() {
final String text = textEditingValue.text;
if (widget.annotations != null) {
var items = getRanges();
var children = <TextSpan>[];
for (var item in items) {
children.add(
TextSpan(style: item.style, text: item.range.textInside(text)),
);
}
return new TextSpan(style: widget.style, children: children);
}
return new TextSpan(style: widget.style, text: text);
}
}
It's also available in this Gist: https://gist.github.com/pulyaevskiy/d7af7217c2e71f31dfb78699f91dfbb5
I actually had the same problem and found the AnnotatedEditbleText which helped me a lot.
I published the helpful package to solve this kind of problem.
https://pub.dev/packages/hashtagable
The TextField does not provide that functionality.
https://pub.dartlang.org/packages/zefyr can do that though.
I think there are some more ''hard'' ways to do this
The first one:
Make a row widget, add a part of the String until the word you want to highlight, add the special word, style it and add the rest of your string.
Or, you could try RichText
Günter post it about the zefyr package, I didn't use it yet, but if suits you, I'll be glad that helped