I am writing a scanner app where the app will be installed on a Scanner that runs Android.
Inside the app there is a TextFormField waiting the input scan or paste in the text inside to do other API call.
However I do not find any option for TextFormField to disable the soft keyboard but still can accept input text
Below is my scanner TextFormField widget code that I have tried.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class BuildScannerBar extends StatefulWidget {
final Function onFieldSubmitted;
final TextEditingController textFieldController;
final String labelText, hintText;
final bool disableKeyboard;
BuildScannerBar({
#required this.textFieldController,
#required this.onFieldSubmitted,
this.disableKeyboard = true,
this.labelText = 'Barcode Scan',
this.hintText = '',
});
#override
_BuildScannerBarState createState() => _BuildScannerBarState();
}
class _BuildScannerBarState extends State<BuildScannerBar> {
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topCenter,
child: Container(
height: 75,
margin: EdgeInsets.only(top: 50),
width: 300
decoration: BoxDecoration(
color: Colors.white,
),
child: ListTile(
title: TextFormField(
controller: widget.textFieldController,
decoration: InputDecoration(
border: InputBorder.none,
labelText: widget.labelText,
hintText: widget.hintText,
onTap: () {
SystemChannels.textInput.invokeMethod('TextInput.hide');
},
onFieldSubmitted: widget.onFieldSubmitted),
),
),
);
}
}
//Create a custom Textfield Widget extending editable:
//=====CUSTOM WIDGET TO HIDE KEYBOARD WHILE ACCEPTING VALUE FOR BARCODE CODE SCANNER DEVICE =====//
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class TextFieldWithNoKeyboard extends EditableText {
TextFieldWithNoKeyboard(
{#required TextEditingController controller,
#required TextStyle style,
#required Function onValueUpdated,
#required Color cursorColor,
bool autofocus = false,
Color selectionColor})
: super(
controller: controller,
focusNode: TextfieldFocusNode(),
style: style,
cursorColor: cursorColor,
autofocus: autofocus,
selectionColor: selectionColor,
backgroundCursorColor: Colors.black,
onChanged: (value) {
onValueUpdated(value);
});
#override
EditableTextState createState() {
return TextFieldEditableState();
}
}
//This is to hide keyboard when user tap on textfield.
class TextFieldEditableState extends EditableTextState {
#override
void requestKeyboard() {
super.requestKeyboard();
//hide keyboard
SystemChannels.textInput.invokeMethod('TextInput.hide');
}
}
// This hides keyboard from showing on first focus / autofocus
class TextfieldFocusNode extends FocusNode {
#override
bool consumeKeyboardToken() {
return false;
}
}
// Use this custom widget in your screen by replacing TextField //with, TextFieldWithNoKeyboard
//=====Below is example to use in your screen ==//
class QRCodeScanner extends StatefulWidget {
QRCodeScanner({Key key}) : super(key: key);
#override
_QRCodeScannerState createState() => _QRCodeScannerState();
}
class _QRCodeScannerState extends State<QRCodeScanner> {
TextEditingController scanController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: TextFieldWithNoKeyboard(
controller: scanController,
autofocus: true,
cursorColor: Colors.green,
style: TextStyle(color: Colors.black),
onValueUpdated: (value) {
print(value);
},
),
),
);
}
}
Just set readOnly to true, and keyboardType to TextInputType.none as shown in the code bellow :
TextFormField(
keyboardType: TextInputType.none,
readOnly: true,
....
Juste add
// readOnly: true
TextFormField(
readOnly: true
controller: widget.textFieldController,
decoration: InputDecoration(
border: InputBorder.none,
labelText: widget.labelText,
hintText: widget.hintText,
onTap: () {
SystemChannels.textInput.invokeMethod('TextInput.hide');
},
onFieldSubmitted: widget.onFieldSubmitted),
),
Related
I am trying to manage some gap between elements and update the gap using setState(). Unfortunately, it did not work with a custom widget TextFieldInput as child of GestureDetector.
GestureDetector(
onTap: () {
setState(() {
gap = 16.00;
});
},
child: TextFieldInput(
textEditingController: _passwordController,
hintText: 'Enter your password',
textInputType: TextInputType.text,
isPass: true,
),
),
But it did work with a Text widget.
GestureDetector(
onTap: () {
setState(() {
gap = smallGap;
});
},
child: Container(
child: Padding(
padding: EdgeInsets.all(5),
child: Text('Tap here'),
),
padding: const EdgeInsets.symmetric(
vertical: 8,
),
),
)
Here is the TextFieldInput widget structure:
import 'package:flutter/material.dart';
class TextFieldInput extends StatefulWidget {
final TextEditingController textEditingController;
final bool isPass;
final String hintText;
final TextInputType textInputType;
final VoidCallback onTap;
const TextFieldInput({
super.key,
required this.textEditingController,
this.isPass = false,
required this.hintText,
required this.textInputType,
required this.onTap,
this.child,
});
final Widget? child;
#override
State<TextFieldInput> createState() => _TextFieldInputState();
}
class _TextFieldInputState extends State<TextFieldInput> {
#override
Widget build(BuildContext context) {
final inputBorder = OutlineInputBorder(
borderSide: Divider.createBorderSide(context)
);
return TextField(
controller: widget.textEditingController,
decoration: InputDecoration(
hintText: widget.hintText,
border: inputBorder,
focusedBorder: inputBorder,
enabledBorder: inputBorder,
filled: true,
contentPadding: const EdgeInsets.all(8),
),
keyboardType: widget.textInputType,
obscureText: widget.isPass,
onTap: () {},
);
}
}
But "gap" does not change even on tapping on the TextFieldInput.
Can anyone help with this ?
Try with a below code snippet:
TextField(
onTap: () {
// To Do
},
// TextField Property
);
gesture detector doesn't work with textField try adding ignorePointer
GestureDetector(
child: new IgnorePointer (
child: new TextField(
.......
))),
onTap: () {
//do some thing
},
The TextField has its onTap property, I think this is the cause of your problem. You should you onTap property of TextField or use another suitable widget
I have a Widget called "CustomInput" that will be massively used through all my app and I'd like to each input to listen to his own FocusNode & apply some conditions whenever the input is focused / unfocused.
Sample example:
class CustomInput extends StatefulWidget {
final String labelText;
final FocusNode focusNode;
final IconData icon;
const CustomInput({String labelText, FocusNode focusNode, IconData icon})
: this.labelText = labelText,
this.focusNode = focusNode,
this.icon = icon;
#override
_CustomInputState createState() => _CustomInputState();
}
class _CustomInputState extends State<CustomInput> {
#override
Widget build(BuildContext context) {
return input();
}
TextFormField input() {
return TextFormField(
focusNode: widget.focusNode,
decoration: InputDecoration(
labelText: widget.labelText,
labelStyle: TextStyle(color: Colors.black54),
fillColor: Colors.white,
filled: true,
prefixIcon: prefixIcon(),
),
);
}
Padding prefixIcon() {
return Padding(
padding: EdgeInsets.only(left: 5),
child: Icon(
widget.icon,
color: widget.focusNode.hasFocus /// <------------- here
? Colors.red
: Colors.black,
size: 20,
),
);
}
}
The goal is to whenever the input is focused, the prefixIcon should assume the red color and when is not focused it should assume the black color. I call the Widget this way:
Column(children: [
CustomInput(
focusNode: emailFocusNode,
icon: Icons.email_outlined,
),
CustomInput(
focusNode: passwordFocusNode,
icon: Icons.lock,
),
/// etc
]);
The problem is that the condition widget.focusNode.hasFocus is not triggering / always valuates to false. I have seen this post How to listen focus change in flutter? and also tried:
bool isFocused = false;
#override
void initState() {
super.initState();
widget.focusNode.addListener(() {
isFocused = widget.focusNode.hasFocus;
});
}
/// and then switch the prefixIcon function to
Padding prefixIcon() {
return Padding(
padding: EdgeInsets.only(left: 5),
child: Icon(
widget.icon,
color: this.isFocused
? Colors.red
: Colors.black,
size: 20,
),
);
}
But the problem persists, it seems the focus listener doesn't get triggered.
Solved. I forgot about the setState 😑
Instead of:
#override
void initState() {
super.initState();
widget.focusNode.addListener(() {
isFocused = widget.focusNode.hasFocus;
});
}
Should be:
#override
void initState() {
super.initState();
widget.focusNode.addListener(() {
setState(() {
isFocused = widget.focusNode.hasFocus
});
});
}
I am creating a login form which has username and password field, i want to add validation when user skip any field. I have created this reusable textfield.
class RoundedInputField extends StatelessWidget {
final String hintText;
final ValueChanged<String> onChanged;
final TextEditingController controller;
final FormFieldValidator validate;
const RoundedInputField({Key key, this.hintText,
this.onChanged,
this.controller,this.validate,
})
: super(key: key);
#override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
onChanged: onChanged,
controller: TextEditingController(),
validator: validate,
decoration: InputDecoration(
hintText: hintText,
border: InputBorder.none,
),
),
);
}
}
and calling it like this
RoundedInputField(hintText: "Username",icon: Icons.email,fontsize: 20,
controller: TextEditingController(text: user.username),
onChanged: (value){
user.username=value;
},
validate: (value){
if(value.isEmpty){
return "This field is required";
}
},
),
but validator property is not working properly, here it is.
please help if anyone know how to fix it!
I have been using TextFormField in a reusable way like this , it has served me for all the purposes i needed , i think it works for your case too
class BoxTextField extends StatelessWidget {
final TextEditingController controller;
final FormFieldValidator<String> validator;
final bool obsecure;
final bool readOnly;
final VoidCallback onTap;
final VoidCallback onEditingCompleted;
final TextInputType keyboardType;
final ValueChanged<String> onChanged;
final bool isMulti;
final bool autofocus;
final bool enabled;
final String errorText;
final String label;
final Widget suffix;
final Widget prefix;
BoxTextField(
{Key key,
this.controller,
this.validator,
this.keyboardType = TextInputType.text,
this.obsecure = false,
this.onTap,
this.isMulti = false,
this.readOnly = false,
this.autofocus = false,
this.errorText,
#required this.label,
this.suffix,
this.prefix,
this.enabled = true,
this.onEditingCompleted,
this.onChanged})
: super(key: key);
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 4),
child: TextFormField(
onChanged: onChanged,
onEditingComplete: onEditingCompleted,
autofocus: autofocus,
minLines: isMulti ? 4 : 1,
maxLines: isMulti ? null : 1,
onTap: onTap,
enabled: enabled,
readOnly: readOnly,
obscureText: obsecure,
keyboardType: keyboardType,
controller: controller,
decoration: InputDecoration(
errorText: errorText,
prefixIcon: prefix,
suffixIcon: suffix,
labelStyle: TextStyle(fontSize: lableFontSize()),
labelText: label,
hintStyle: TextStyle(color: Colors.blueGrey, fontSize: 15),
contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 20),
enabledBorder: textFieldfocused(),
border: textFieldfocused(),
focusedBorder: textFieldfocused(),
errorBorder: errorrTextFieldBorder(),
focusedErrorBorder: errorrTextFieldBorder(),
),
validator: validator),
);
}
}
This is the Usage
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController _emailPhone = new TextEditingController();
TextEditingController _password = new TextEditingController();
GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
#override
void initState() {
super.initState();
}
String loginError;
bool loggingIn = false;
#override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate([
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 50,
),
BoxTextField(
validator: (str) {
if (str.isEmpty) {
return tr('common.required');
}
return null;
},
controller: _emailPhone,
label: tr('login.username'),
),
SizedBox(
height: 10,
),
BoxTextField(
label: tr('login.password'),
controller: _password,
obsecure: true,
validator: (str) {
if (str.isEmpty) {
return tr('common.required');
}
return null;
},
),
Center(
child: BoxButton(
loading: loggingIn,
lable: tr('login.btn'),
onPressed: () {
},
)),
],
)),
)
]))
],
);
}
}
Replace your code and try this:
RoundedInputField(
hintText: "Username",
icon: Icons.email,
fontsize: 20,
controller: TextEditingController(text: user.username),
onChanged: (value) {
user.username = value;
},
validate: (value) {
if (value.isEmpty) {
return "This field is required";
}
return null;
},
),
As per: How to shift focus to next textfield in flutter?, I used FocusScope.of(context).nextFocus() to shift focus. But this doesn't work when you use a reusable textfield class. It only works when you directly use TextField class inside Column.
import 'package:flutter/material.dart';
void main() {
return runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final focus = FocusScope.of(context);
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
CustomTextField(
textInputAction: TextInputAction.next,
onEditingComplete: () => focus.nextFocus(),
),
const SizedBox(height: 10),
CustomTextField(
textInputAction: TextInputAction.done,
onEditingComplete: () => focus.unfocus(),
),
],
),
),
),
);
}
}
class CustomTextField extends StatelessWidget {
final TextInputAction textInputAction;
final VoidCallback onEditingComplete;
const CustomTextField({
this.textInputAction = TextInputAction.done,
this.onEditingComplete = _onEditingComplete,
});
static _onEditingComplete() {}
#override
Widget build(BuildContext context) {
return TextField(
textInputAction: textInputAction,
onEditingComplete: onEditingComplete,
);
}
}
In this code, if I click next in keyboard it will not shift focus to next textfield. Please help me with this.
That's because the context doesn't have anything it could grab the focus from. Replace your code with this:
void main() => runApp(MaterialApp(home: MyApp()));
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final focus = FocusScope.of(context);
return Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
CustomTextField(
textInputAction: TextInputAction.next,
onEditingComplete: () => focus.nextFocus(),
),
SizedBox(height: 10),
CustomTextField(
textInputAction: TextInputAction.done,
onEditingComplete: () => focus.unfocus(),
),
],
),
);
}
}
You need to wrap your fields in a form widget with a form key and use a TextFormField instead of textField widget. Set the action to TextInputAction.next and it should work! You can also use TextInput.done to trigger the validation.
Here a fully working exemple:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class LogInPage extends StatefulWidget {
LogInPage({Key key}) : super(key: key);
#override
_LogInPageState createState() => _LogInPageState();
}
class _LogInPageState extends State<LogInPage> {
final _formKey = new GlobalKey<FormState>();
bool isLoading = false;
String firstName;
String lastName;
String password;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
backgroundColor: Colors.black,
body: body(),
);
}
Widget body() {
return Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
showInput(
firstName,
TextInputType.name,
Icons.drive_file_rename_outline,
"FirstName",
TextInputAction.next,
onSaved: (value) => firstName = value.trim()),
showInput(lastName, TextInputType.name,
Icons.drive_file_rename_outline, "LastName", TextInputAction.next,
onSaved: (value) => lastName = value.trim()),
showInput(null, TextInputType.text, Icons.drive_file_rename_outline,
"Password", TextInputAction.done,
isPassword: true, onSaved: (value) => password = value),
Padding(
padding: EdgeInsets.symmetric(vertical: 10),
),
showSaveButton(),
],
),
);
}
Widget showInput(String initialValue, TextInputType textInputType,
IconData icon, String label, TextInputAction textInputAction,
{#required Function onSaved, bool isPassword = false}) {
return Padding(
padding: EdgeInsets.fromLTRB(16.0, 20.0, 16.0, 0.0),
child: new TextFormField(
style: TextStyle(color: Theme.of(context).primaryColorLight),
maxLines: 1,
initialValue: initialValue,
keyboardType: textInputType,
textInputAction: textInputAction,
autofocus: false,
obscureText: isPassword,
enableSuggestions: !isPassword,
autocorrect: !isPassword,
decoration: new InputDecoration(
fillColor: Theme.of(context).primaryColor,
hintText: label,
hintStyle: TextStyle(color: Theme.of(context).primaryColorDark),
filled: true,
contentPadding: new EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(12.0),
),
icon: new Icon(
icon,
color: Theme.of(context).primaryColorLight,
)),
validator: (value) {
return value.isEmpty && !isPassword
? "You didn't filled this field."
: null;
},
onSaved: onSaved,
onFieldSubmitted:
textInputAction == TextInputAction.done ? (value) => save() : null,
),
);
}
Widget showSaveButton() {
return RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(100))),
color: Theme.of(context).primaryColor,
padding: EdgeInsets.symmetric(vertical: 12, horizontal: 25),
child: isLoading
? SizedBox(height: 17, width: 17, child: CircularProgressIndicator())
: Text(
"Sauvegarder",
style: TextStyle(color: Theme.of(context).primaryColorLight),
),
onPressed: save,
);
}
void save() async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
//TODO
}
}
}
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
This is my code.When I try to get RxInput.value,I get nothing.How to deal with it?Where is the problem?
I want to make it easy for me to use the decorated textfield.So I build this class.How to solve it????
I am about to be crazy.
import 'package:flutter/material.dart';
class RxInput {
_RxInput rx;
final String hindText;
final bool obscureText;
Widget get widget => rx;
final TextEditingController controller = new TextEditingController ();
String get value => controller.text;
RxInput (this.hindText,context,{this.obscureText = false}) {
rx = _RxInput (hindText,obscureText,controller);
}
}
class _RxInput extends StatefulWidget{
final TextEditingController controller;
_RxInput (this.hindText,this.obscureText,this.controller);
final String hindText;
final bool obscureText;
#override
createState () {
return _RxInputState ();
}
}
class _RxInputState extends State <_RxInput>{
Padding data;
#override
void initState() {
data = Padding (
padding: const EdgeInsets.all(20.0),
child: Material(
borderRadius: BorderRadius.circular(20.0),
shadowColor: Colors.blue.shade200,
elevation: 5.0,
child:TextField(
controller: widget.controller,
decoration: InputDecoration(
hintText: widget.hindText,
border: InputBorder.none,
alignLabelWithHint: true,
),
obscureText: widget.obscureText,
)
),
);
super.initState();
}
#override
Widget build(BuildContext context) {
return data;
}
}
Do like this
1. Create a Class with Meaningful Name for eg.Helper Class
2. And Implement below Textfield Method
Widget textField(String hint, TextEditingController controller,
{TextInputType keyboardType = TextInputType.text,
bool obscure = false,
VoidCallback onEditingComplete}) {
return SizedBox(
height: 45,
child: TextField(
onEditingComplete: onEditingComplete,
obscureText: obscure,
controller: controller,
keyboardType: keyboardType,
decoration: InputDecoration(
contentPadding: textFieldPadding(),
hintText: hint,
border: OutlineInputBorder(),
),
inputFormatters: [LengthLimitingTextInputFormatter(maxLength)],
),
);
}
And just simply use it by importing a particular class library put it wherever you want and let me know it is working for you or not?