I need to scan data through a physical device using flutter textfield, but I don't have a solution yet I have gone through many and nothing works for me, please someone helps with this.
TextFormField(
focusNode: loginTextfieldFocus,
style: const TextStyle(fontSize: 15),
controller: loginTextController,
decoration: decoration(context, loginTextController),
onChanged: (val) {
if (val.contains('\n') || val.contains('\r')) {
Log.d("LoginTextfield Entered");
}
},
),
This is not the proper way to do , but somehow i managed to do it.
TextFormField(
autofocus: true,
enabled: isEditable,
showCursor: isEditable,
readOnly: true,
keyboardType: TextInputType.none,
focusNode: textfieldFocus,
controller: textfieldCtr
),
//Called this under widget build
#override
Widget build(BuildContext context) {
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
FocusScope.of(context).requestFocus( textfieldFocus);
});
To receive scan data from device i used RawKeyboardListener. For scanning you can refer it here (flutter Enter event not found on zebra tc77?)
Yes, I have the same issue. I have solve by changing onChanged to validator because onChange is keep reloading your state thatswhy your keyboard is automatically dismiss every time.
validator: (value) {
if (value != null && value.trim().length < 10) {
return 'This field requires a minimum of 10 characters';
}
return null;
},
Try this
Widget build(BuildContext context) {
Future.delayed(const Duration(), () => SystemChannels.textInput.invokeMethod('TextInput.hide'));
return Scaffold(
body: TextField(
autofocus: true,
),
);
}
Related
I have a TextField like this. The additional code is necessary to show that in different situations, I do various focus manipulation.
final node = FocusScope.of(context);
Function cleanInput = () => {controller.text = controller.text.trim()};
Function onEditingComplete;
Function onSubmitted
TextInputAction textInputAction;
if (!isLast) {
onEditingComplete = () => {
cleanInput(),
node.nextFocus(),
};
onSubmitted = (_) => {cleanInput()};
textInputAction = TextInputAction.next;
} else {
onEditingComplete = () => {
cleanInput(),
};
onSubmitted = (_) => {
cleanInput(),
node.unfocus(),
};
textInputAction = TextInputAction.done;
}
Widget textInput = TextField(
textInputAction: textInputAction,
controller: controller,
onEditingComplete: onEditingComplete,
onSubmitted: onSubmitted,
keyboardType: textInputType,
));
As you can see, I have functions I want to run onEditingComplete. However, this only gets called when I press the Next or Done buttons on my keyboard (or the Enter key in an emulator). If I change focus by tapping on a different field, this function does not get called.
I have tried using a Focus or FocusNode to help with this, but when I do so, the onEditingComplete function itself no longer works.
How can I get the desired effect here while everything plays nicely together?
Focus widget
Wrapping fields in a Focus widget might do the trick.
The Focus widget will capture focus loss events for children. With its onFocusChange argument you can call arbitrary functions.
Meanwhile, the onEditingComplete argument of TextField is unaffected and will still be called on the software keyboard "Next/Done" keypress.
This should handle field focus loss for both "Next/Done" keypress and user tapping on another field.
import 'package:flutter/material.dart';
class TextFieldFocusPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// ↓ Add this wrapper
Focus(
child: TextField(
autofocus: true,
decoration: InputDecoration(
labelText: 'Name'
),
textInputAction: TextInputAction.next,
// ↓ Handle focus change on Next / Done soft keyboard keys
onEditingComplete: () {
print('Name editing complete');
FocusScope.of(context).nextFocus();
},
),
canRequestFocus: false,
// ↓ Focus widget handler e.g. user taps elsewhere
onFocusChange: (hasFocus) {
hasFocus ? print('Name GAINED focus') : print('Name LOST focus');
},
),
TextField(
decoration: InputDecoration(
labelText: 'Password'
),
),
],
),
),
),
);
}
}
Please add a focus node to your textfield and add a listener to your focus node to trigger when it unfocuses
final node = FocusScope.of(context);
node.addListener(_handleFocusChange);
void _handleFocusChange() {
if (node.hasFocus != _focused) {
setState(() {
_focused = node.hasFocus;
});
}
}
Widget textInput = TextField(
//you missed this line of code
focusNode: node,
textInputAction: textInputAction,
controller: controller,
onEditingComplete: onEditingComplete,
onSubmitted: onSubmitted,
keyboardType: textInputType,
));
And also you can validete automatically by adding autoValidate to your code like below:
Widget textInput = TextField(
//add this line of code to auto validate
autoValidate: true,
textInputAction: textInputAction,
controller: controller,
onEditingComplete: onEditingComplete,
onSubmitted: onSubmitted,
keyboardType: textInputType,
));
FocusNode _node;
bool _focused = false;
#override
void initState() {
super.initState();
_node.addListener(_handleFocusChange);
}
void _handleFocusChange() {
if (_node.hasFocus != _focused) {
setState(() {
_focused = _node.hasFocus;
});
}
}
#override
void dispose() {
_node.removeListener(_handleFocusChange);
_node.dispose();
super.dispose();
}
TextFormField(
focusNode: _node)
I'm working on a Flutter Web application which includes chat.
I'd like to include an ordinary input function where users can enter text and send it into the chat stream. A standard feature of chat apps these days is to send on <ENTER> and to perform a line break on <SHIFT-ENTER>, or some variation of this.
Currently I've only been able to achieve one of these functions at a time. If you set the TextField's keyboardType to TextInputType.multiline then <ENTER> and <SHIFT-ENTER> always perform a line-break, there doesn't appear to be a way to override this behavior.
If instead your TextField is TextInputType.text you can capture <ENTER> and send, but trying to capture <SHIFT-ENTER> to add a line-break has not worked. I've tried manually grabbing the key press via an onKey handler and inserting \n to the controller.text, but it appears that TextInputType.text is not meant for multiline at all, so it doesn't play well.
Just wondering if any other devs have run into this or come up with any suitable solutions. Ideally a solution would also work across android/ios. For me, I've decided to go with TextInputType.text and forgo the multiline functionality for now.
Thanks
For what it's worth, I was able to concoct a reasonable solution that I'll post below in case anyone runs into this themselves.
I wrapped the Textfield in a keyboard listener which calls my onSend function when it see's an <Enter>. I tried this before, but I guess earlier I was missing the cast to RawKeyEventDataWeb which allowed me to capture isShiftPressed to allow for new lines on <SHFT-ENTER> without forcing a send. Unfortunately I had to add some hacky code to remove the \n that's added when pressing enter, but that's a small price to pay for functional + modern messaging.
RawKeyboardListener(
focusNode: focusNode,
onKey: handleKeyPress,
child: TextField(
controller: messageController,
minLines: 1,
maxLines: null,
textInputAction: TextInputAction.done,
style: normalTextStyle,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
isDense: true,
hintText: 'Type a message',
hintStyle: TextStyle(
fontSize: 16,
color: Color(0xFF474749),
),
border: InputBorder.none,
),
),
)
void handleKeyPress(event) {
if (event is RawKeyUpEvent && event.data is RawKeyEventDataWeb) {
var data = event.data as RawKeyEventDataWeb;
if (data.code == "Enter" && !event.isShiftPressed) {
final val = messageController.value;
final messageWithoutNewLine =
messageController.text.substring(0, val.selection.start - 1) +
messageController.text.substring(val.selection.start);
messageController.value = TextEditingValue(
text: messageWithoutNewLine,
selection: TextSelection.fromPosition(
TextPosition(offset: messageWithoutNewLine.length),
),
);
_onSend();
}
}
}
This can be achieved by adding a FocusNode to the TextField. Place the focus node in your widget's state.
late final _focusNode = FocusNode(
onKey: (FocusNode node, RawKeyEvent evt) {
if (!evt.isShiftPressed && evt.logicalKey.keyLabel == 'Enter') {
if (evt is RawKeyDownEvent) {
_sendMessage();
}
return KeyEventResult.handled;
}
else {
return KeyEventResult.ignored;
}
},
);
In your build function add the focus when creating the TextField.
TextField(
autofocus: true,
controller: _textController,
focusNode: _focusNode,
)
This is what I am using in my TextField to support newline on enter.
class TextInputsWidget extends StatelessWidget {
final TextEditingController chatTextFieldController = TextEditingController();
late final _focusNode = FocusNode(
onKey: _handleKeyPress,
);
KeyEventResult _handleKeyPress(FocusNode focusNode, RawKeyEvent event) {
// handles submit on enter
if (event.isKeyPressed(LogicalKeyboardKey.enter) && !event.isShiftPressed) {
_sendMessage();
// handled means that the event will not propagate
return KeyEventResult.handled;
}
// ignore every other keyboard event including SHIFT+ENTER
return KeyEventResult.ignored;
}
void _sendMessage() {
if (chatTextFieldController.text.trim().isNotEmpty) {
// Do something with your input text
print(chatTextFieldController.text.trim());
// bring focus back to the input field
Future.delayed(Duration.zero, () {
_focusNode.requestFocus();
chatTextFieldController.clear();
});
}
}
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
textInputAction: TextInputAction.newline,
autofocus: true,
focusNode: _focusNode,
controller: chatTextFieldController,
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.fromLTRB(8, 0, 0, 0),
hintText: "Enter your message here",
hintStyle: TextStyle(color: Colors.black54),
),
),
);
}
}
There are mainly 3 key changes
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.newline,
FocusNode which can listen to keyboard events
The best way to have the Enter key be disabled for the input and instead send it when no ctrl key is pressed is through the focusNode directly on the input, this way you won't have to remove extra new lines.
class _InputTextState extends State<InputText> {
late final _focusNode = FocusNode(onKey: handleKeyPress);
#override
Widget build(BuildContext context) {
return TextField(
focusNode: _focusNode,
);
}
KeyEventResult handleKeyPress(FocusNode focusNode, RawKeyEvent event) {
// handles submit on enter
if (kIsWeb &&
event.isKeyPressed(LogicalKeyboardKey.enter) &&
!event.isControlPressed &&
!event.isShiftPressed) {
widget.onSubmit();
// handled means that the event will not propagate
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
}
}
How to autovalidate a text form field when its value changes?
i tried
bool _autoValidate = false;
TextFormField(
autovalidate: _autoValidate ,
onChanged: (value) {
setState(() {
_autoValidate = true;
});
},
validator: (value) {
if (value.length < 5) {
return 'False';
} else {
return 'True';
}
},
),
But not working, TextFormField still doesn't show errors on validation.
I need a way to turn on the validation on text changed.
Flutter has nows an API to validate a form field only when the content changes. You just need to use the autovalidateMode parameter and set it to AutovalidateMode.onUserInteraction.
The following text field will only validate when the user changes its content:
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
),
),
);
}
}
See AutovalidateMode docs for more options in when to validate.
This API is now available on the latest stable channel. Let me know if it solves your problem.
I think,
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
)
is the best way to solve this issue.
I have a problem while developing my app - how can I auto-focus a textfield after completing input on the previous field, without having to click the textfield?
Use focusNode property and onEditingComplete event. Event trigger after user click on enter on first textfield, after that focusNode request focus for the second TextField.
For example:
FocusNode focusNode = FocusNode();
#override
Widget build(BuildContext context) => Scaffold(
body: Column(
children: <Widget>[
TextField(
autofocus: true,
onEditingComplete: (() => focusNode.requestFocus())
),
TextField(
focusNode: focusNode,
)
]
)
);
More info at: https://flutter.dev/docs/cookbook/forms/focus
TextField(
onEditingComplete: () => FocusScope.of(context).nextFocus(),
),
For the last textfield you would change the 'nextFocus()' to 'unfocus()'
return Focus(
child: TextField(
onChanged: (value) => context.read<SignupBloc>().add(SignupPasswordChanged(value)),
controller: controller,
keyboardType: TextInputType.visiblePassword,
obscureText: true,
key: const Key('signupForm_passwordInput_textField'),
decoration: InputDecoration(
labelText: 'Password *',
errorText: state.password.invalid
? 'Passwords must be at least 10 characters in length\nand a minimum of 1 '
'upper case and 1 lower case letter [A-Za-z]'
: null,
),
),
);
you can also try with
textInputAction: TextInputAction.next
in TextFormField
I have two textFormField widgets. Once the user has completed the first text field I would like to focus on the next textField. Is there a way to do this in Flutter? Currently, the done button just closes the keyboard. I was guessing the focusNode class might be the answer to this but not really sure how that works does anyone have any good examples of focusNode class? Thanks in advance.
Yes, FocusNode and the onFieldSubmitted from a TextFormField are probably the way to go.
FocusScope.of(context).requestFocus(focusNode);
Here is an example that may help:
FocusNode textSecondFocusNode = new FocusNode();
TextFormField textFirst = new TextFormField(
onFieldSubmitted: (String value) {
FocusScope.of(context).requestFocus(textSecondFocusNode);
},
);
TextFormField textSecond = new TextFormField(
focusNode: textSecondFocusNode,
);
// render textFirst and textSecond where you want
You may also want to trigger FocusScope.of() from a button rather than onFieldSubmitted, but hopefully the above example gives you enough context to construct an appropriate solution for your use case.
Screenshot:
No need to use FocusNode
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
TextField(
decoration: InputDecoration(hintText: 'First Name'),
textInputAction: TextInputAction.next,
onEditingComplete: () => FocusScope.of(context).nextFocus(),
),
TextField(
decoration: InputDecoration(hintText: 'Last Name'),
textInputAction: TextInputAction.done,
onSubmitted: (_) => FocusScope.of(context).unfocus(),
),
],
),
);
}
There's a similar method like in Android.
Add
textInputAction
parameter to the TextFormField Widget, then add the property as;
TextInputAction.next
This is how I did it:
var _focusNodes = List.generate(6, (index) => FocusNode()));
And in the TextFormField:
TextFormField(
focusNode: _focusNodes[i],
maxLines: 1,
textInputAction: TextInputAction.next,
onChanged: (text) {
if (i < _controllers.length) {
if (text.isEmpty)
_focusNodes[i - 1].requestFocus();
else
_focusNodes[i + 1].requestFocus();
}
},
),