Flutter Call Listener from another class - flutter

I am pretty new to Flutter (coming from Java) and making my way through the first Android application.
In my project, I am using a different class to create a reusable widget (from the example here), that works perfectly with all methods, but I can't figure out a way to define and reuse the method onEditingComplete.
Here is my code:
class AppTextField extends StatelessWidget {
//
AppTextField({
this.controller,
this.textInputType,
this.pwValidator,
this.editingComplete, // this the method that is causing the problem
});
final TextEditingController controller;
final TextInputType textInputType;
final FormFieldValidator pwValidator;
final Listener editingComplete; // This doesn't work. Am I using the wrong listener?
#override
Widget build(BuildContext context) {
return Container(
child: Theme(
data: ThemeData(
primaryColorDark: Colors.blue,
),
child: Padding(
padding: EdgeInsets.fromLTRB(25, 15, 25, 0),
child: TextFormField(
controller: controller,
keyboardType: null == textInputType ? textInputType : textInputType,
validator: null == pwValidator ? pwValidator : pwValidator,
// I am facing problems with this line of code
onEditingComplete: null == editingComplete ? editingComplete : editingComplete,
),
),
),
);
}
}
This is the class where I want to implement and reuse the widget :
Container(
child: AppTextField(
controller: _controllerPassword,
pwValidator: (value) { },
onEditingComplete: // here is where I am facing difficulties
),

The property onEditingComplete is a VoidCallback. Which is a function without parameter and does not return any data.
In AppTextField define onEditingComplete as
final VoidCallback onEditingComplete;
Then assign it to the onEditingComplete property of the TextFormField. Also, get rid of the ternary operators.
onEditingComplete: onEditingComplete
And when using the widget, pass the callback like so:
Container(
child: AppTextField(
controller: _controllerPassword,
pwValidator: (value) { },
onEditingComplete: (){
//Do what you want to do here.
}
),

Related

Flutter: Position Counter for TextFormField

I'm currently trying to move the TextFormField counter to the top (above the actual input box), and I'm unsure on how to do so.
Currently:
So the counter should be moved up to the top right corner above the input box field. I tried to think about building a new counter but there must be an easier way to do this? I also tried experimenting with InputDecoration but nothing seems to really work.
TextFormField(
maxLength: 1000,
decoration: InputDecoration(
labelText: label,
labelStyle: TextStyle(fontSize: 30,
),
)
Would appreciate some help, thanks in andvance!
A shortcut way is using buildCounter with transform. But this will contain some extra spaces, and I think it's kinda ok.
TextFormField(
maxLength: 1000,
buildCounter: (context,
{required currentLength, required isFocused, maxLength}) {
return Container(
transform: Matrix4.translationValues(0, -kToolbarHeight, 0),
child: Text("$currentLength/$maxLength"),
);
},
),
Another way TextEditingController and Column
final TextEditingController controller = TextEditingController();
final maxLength = 1000;
#override
void initState() {
controller.addListener(() {
setState(() {});
});
super.initState();
}
Column(
children: [
Align(
alignment: Alignment.centerRight,
child: Text("${controller.text.length}/$maxLength"),
),
TextFormField(
key: ValueKey("textFiled in Column"),
controller: controller,
buildCounter: (context,
{required currentLength,
required isFocused,
maxLength}) =>
SizedBox(),
),
],
),
Result

FORMS, no further idea how to implement a TextField with a CupertinoApp

This drives me nuts. I am trying to get a CupertinoTextField into a Form. But no matter what I try, everything turns out as a dead end.
The complication of my case is, the form in embedded into the Flushbar package, which provides kind of a snackbar to my CupertinoApp. And this is a stateless widget ;-(
return Flushbar(
backgroundColor: Common.inputBlue,
userInputForm : Form(
key: _formKey,
child: Column(
children: <Widget> [
_DelayStatusFormField(
initialValue: task.delayStatus,
onSaved: (value) => otherFormDataSubmit.delayStatus = value,
//onSaved: (value) => this.delayStatus = value,
),
CupertinoTextField(
controller: _delayTec,
onChanged: (text) {
state.didChange(text);
},
),
]),
),
);
In the onChanged section I intend to implement some validation, so I need kind of a rebuild. But setState obviously doesn't work without a proper state.
Using TextFormField also looks kind of dodgy, because I do not only have to embed this in Material( but in loads of further localization Widgets.
The most desirable solution, is this one where I tried several variants: embed the CupertinoTextField in a FormField class
class _DelayFormField extends FormField<String> {
_DelayFormField({
FormFieldSetter<String> onSaved,
String initialValue,
bool enabled,
GlobalKey key,
}) : super(
onSaved: onSaved,
initialValue: initialValue,
key: key,
builder: (FormFieldState<String> state) {
//TextEditingController inputTec = TextEditingController(text: initialValue);
return Column(children: [
SizedBox(
width: 100, height: 30,
child: CupertinoTextField(
//controller: inputTec,
enabled: true,
onChanged: (text) {
initialValue = text;
state.didChange(text);
},
)),
]);
}
);
}
The problem here, I the TextEditingController is reinitialized on any rebuild with initialVale, loosing my input. I have got around this by assigning the input to initialVale, but the cursor is then always set leading to the prefilled digits. So you type the number backwards. Since everything is in the class' initialization, I cannot find a spot where to initialize the TextEditingController outside of the build method.
Any other idea on how to solve this? Getting such a class working would be great, since one could then simply re-use this class, frequently.

Flutter enabled and focus textformfield

I create a profile page and i have 4 textformfield. I want to on tap icon activate textformfield and focus at the same time. Now I need tap twice on icon and first activated field, secondly focused.
How to solve it?
My code:
class UserProfile extends StatefulWidget {
#override
_UserProfileState createState() => _UserProfileState();
}
class _UserProfileState extends State<UserProfile> {
FocusNode myFocusNode;
bool isEnable = false;
#override
void initState() {
super.initState();
myFocusNode = FocusNode();
}
#override
void dispose() {
myFocusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.fromLTRB(40.0, 50.0, 20.0, 0.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Flexible(
child: TextFormField(
enabled: isEnable,
focusNode: myFocusNode,
),
),
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
setState(() {
isEnable = true;
FocusScope.of(context).requestFocus(myFocusNode);
});
})
],
),
You should use autofocus: isEnable instead.
just do like below in your ontap
setState(() {
if(isEnable)
Future.delayed(const Duration(milliseconds: 10), ()
{FocusScope.of(context).requestFocus(myFocusNode);
});
isEnable = true;
});
in first time isEnable is false so focusing not call and just enabling work and in other times get focus too.
you can't focus widget until disabled and when you enabling widget. when you do focusing and enabling at same time in ui tread it's try focusing before enabling because of their rendering time.if you post some delay to focusing the problem get solving.
Try using readOnly instead of enabled in TextFormField
I faced similar issue when I had multiple TextFields to enable kinda PIN input. And some of that had to be dynamically enabled and disabled plus prevent users from entering value in the next field while they haven't finished the previous one. I've tried a lot of approaches and focusing field after some delay was not a way to go because I wanted the keyboard to always be available while entering. So I've took a crazy path and solved this next way:
onTap: () => _focusNodes[_currentLetterIndex].requestFocus()
where _focusNodes are for each letter and _currentLetterIndex is calculated programmatically during input (when finished letter 0 -> current becomes 1 and so on). As the result when user tried to tap on next field - it was automatically refocused to the current one which behaves like the next field is disabled.
An example of the full text field looks like this (don't pay attention to decorations etc.)
TextField(
key: ValueKey(index),
controller: _editingControllers[index],
onTap: () => _focusNodes[_currentLetterIndex].requestFocus(),
focusNode: _focusNodes[index],
textAlign: TextAlign.center,
showCursor: false,
maxLength: 2,
enableInteractiveSelection: false,
autocorrect: false,
enableSuggestions: false,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
height: 1.2,
decoration: TextDecoration.none),
decoration: InputDecoration(
fillColor: !_wordCompleted &&
!correct &&
_editingControllers[index].text.isNotEmpty
? const Color(0xFFFFEEF0)
: Colors.white,
filled: !correct,
counterText: "",
border: defaultInputBorder,
focusedBorder: !correct &&
!_wordCompleted &&
_editingControllers[index].text.isNotEmpty
? incorrectInputBorder
: focusedInputBorder,
enabledBorder: _wordCompleted
? focusedInputBorder
: correct
? correctInputBorder
: defaultInputBorder,
errorBorder: defaultInputBorder,
disabledBorder: _wordCompleted
? focusedInputBorder
: correct
? correctInputBorder
: defaultInputBorder,
contentPadding: const EdgeInsets.only(left: 2)),
),

Flutter using EditableText

I'm trying to figure out how to use the TextEditor in Flutter.
I have "Card Editor" (basically I want to be able to work on the equivalent of a paragraph of text)
new EditableText(
autofocus: true,
maxLines: null,
backgroundCursorColor: Colors.amber,
cursorColor: Colors.green,
style: TextStyle(),
focusNode: FocusNode(),
controller: controller,
onSubmitted: (val) {
_addCard(val);
Navigator.pop(context);
},
)
I adapted this from an example of a TextField.
But I have a couple of questions.
Firstly, it doesn't seem to show anything when I type. The cursor moves, but no text is visible. Is that the default when there's no explicit style?
Secondly, how do I trigger the submit? With a TextField, the CR / Enter button does this. Obviously I see why you don't necessarily want that with EditableText But what should I do instead?
Third, I need to be able to put default text into this widget. I tried adding a "value" attribute to the EditableText, but that doesn't seem to be right. What's the way to do this?
from TextField class - material library - Dart API :
EditableText, which is the raw text editing control at the heart of a TextField. The EditableText widget is rarely used directly unless you are implementing an entirely different design language, such as Cupertino.
here an example of TextField , from my app flutter listview CRUD app using nonsecure rest api
class _TaskEditPageWidgetState extends State<TaskEditPageWidget> {
TextEditingController _noteController;
#override
void initState() {
super.initState();
_noteController = TextEditingController.fromValue(
TextEditingValue(
text: widget.taskOpj.note,
),
);
}
#override
void dispose() {
_noteController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar(),
body: _body(),
);
}
Widget _appBar() {
return AppBar(
title: new Text("Edit Task"),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.save),
onPressed: _save,
),
],
);
}
Widget _body() {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Text("Note:"),
TextField(
decoration: InputDecoration(border: InputBorder.none),
autofocus: true,
keyboardType: TextInputType.multiline,
maxLines: null,
controller: _noteController),
],
),
);
}
Future _save() async {
widget.taskOpj.note = _noteController.text;
await Tasks.updateTask(widget.taskOpj);
widget.notifyParent();
Navigator.pop(context);
}
}
Just add this line:
style: TextStyle(
decorationThickness: 0.001,
),

Flutter update countertext

In Flutter, inputDecoration's countertext property does not change as the user is typing in the TextFormField. Is it possible to decrement the countertext as the user is typing?
TextFormField(
keyboardType: TextInputType.number,
decoration: new InputDecoration(
counterText: "9",
hintText: "Enter exact order number",
),
)
I edit this answer to work with your question
class StackEditText extends StatefulWidget {
#override
_StackEditTextState createState() => _StackEditTextState();
}
class _StackEditTextState extends State<StackEditText> {
TextEditingController _controller = new TextEditingController();
void onValueChange() {
setState(() {
_controller.text;
});
}
#override
void initState() {
super.initState();
_controller.addListener(onValueChange);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: TextFormField(
controller: _controller,
maxLength: 9,
decoration: InputDecoration(
counterText: "${9 - _controller.text.length}",
hintText: 'Enter exact order number',
),
),
),
);
}
}
I do not recommend using the decoration: InputDecoration::counterText. You have to use setState or whatever to manually update the counter that way.
Instead, I recommend the maxLength property, that automatically makes a counter and updates it:
TextField(maxLength: 8)
Result:
This might be what most people want.
You can even further customize it with the buildCounter parameter, to return whatever widget you want when the text length changes. For example, if you only want to display how many characters left, you can do this:
TextField(
maxLength: 8,
buildCounter: (
BuildContext context, {
int currentLength,
int maxLength,
bool isFocused,
}) {
return Text('${maxLength - currentLength}');
},
)