Related
How to show a constant text in textfield in Flutter along with typed data like in this picture.
You can use String Interpolation. Using $ to access variable in Text Widget.
#override
Widget build(BuildContext context) {
double quantity = 1;
return Row(
children: [
Icon(Icons.production_quantity_limits_outlined),
SizedBox(
width: 20,
),
Text("$quantity (qty)"),
],
);
}
class Example extends StatelessWidget {
const Example({super.key});
#override
Widget build(BuildContext context) {
double quantity = 1;
return TextField(
decoration: InputDecoration(
label: Text("$quantity (qty)"),
border: OutlineInputBorder()
),
);
}
}
you can use like this:
class TextFieldExample extends StatelessWidget {
const TextFieldExample({Key? key}) : super(key: key);
Widget build(BuildContext context) {
TextEditingController? controller;
return Scaffold(
body: Padding(
padding: EdgeInsets.all(20),
child: TextField(
controller: controller,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
),
filled: true,
hintText: '1(qty)',
prefixIcon: Icon(Icons.watch),
),
),
),
);
}
}
I am newbie at Dart and OOP.I have one input.dart file for Text Form Fields and login.dart file to conduct login.My problem is I want to acces text controller (located in input.dart) from login.dart.
I created getter method to obtain, (controller.text) data but I have encountered with Initilazation Error.
How Can I acces controller text(which is basically user input) from another file?
input.dart
class InputAlanState extends State<InputAlan> {
late TextEditingController _emailKontroller;
late TextEditingController _sifreKontroller;
#override
void initState() {
super.initState();
_emailKontroller = TextEditingController();
_sifreKontroller = TextEditingController();
}
#override
void dispose() {
_emailKontroller.dispose();
_sifreKontroller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
if (widget.tur == "email") {
return Padding(
padding: const EdgeInsets.only(top: 50, left: 20, right: 20),
child: TextFormField(
controller: _emailKontroller,
autofocus: true,
decoration: const InputDecoration(
labelText: "E - Mail",
hintText: "E-Mail",
prefixIcon: Icon(Icons.email_outlined),
suffixIcon: Icon(Icons.lock),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)))),
),
);
} else if (widget.tur == "sifre") {
return Padding(
padding:
const EdgeInsets.only(top: 40, left: 20, right: 20, bottom: 15),
child: TextFormField(
controller: _sifreKontroller,
obscureText: true,
decoration: const InputDecoration(
labelText: "Password",
hintText: "Password",
prefixIcon: Icon(Icons.password_sharp),
suffixIcon: Icon(Icons.lock),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)))),
),
);
} else {
return Padding(
padding: const EdgeInsets.only(top: 50, left: 20, right: 20),
child: TextFormField(
decoration: const InputDecoration(
labelText: "E - Mail",
hintText: "E-Mail",
prefixIcon: Icon(Icons.email_outlined),
suffixIcon: Icon(Icons.lock),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)))),
),
);
}
}
}
login.py
Widget build(BuildContext context) {
return OutlinedButton(
onPressed: () {
InputAlan inputAlan = InputAlan("email");
String email = inputAlan.email;
String password = inputAlan.sifre;
Login login = login(email, sifre);
girisYap.girisYap(context);
},
child: const Text("SIGN IN"),
style: OutlinedButton.styleFrom(
primary: const Color(0xFF166FC0),
side: const BorderSide(color: Color(0xFF0FA9EA), width: 2),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)))),
);
}
}
to access variables from another state (in your case from InputAlanState) in flutter you have multiple options, the simplest way would be to use a GlobalKey, so in your code you can access InputAlanState's controllers from your login you can use this code in your OutlinedButton:
GlobalKey<InputAlanState> myKey = GlobalKey();
myKey.currentState!._emailKontroller; //here
You're putting a widget in a function parameter. In this way the widget cannot be rendered and it just can't work. I suggest you take a look at how to build flutter layouts to grasp the basics.
You probably want to build something like this:
enum Field { mail, password }
class MyApp extends StatelessWidget {
final TextEditingController mailController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
InputAlan(fieldType: Field.mail, textEditingController: mailController,),
InputAlan(fieldType: Field.password, textEditingController: passwordController,),
OutlinedButton(
onPressed: () {
String email = mailController.text;
String sifre = passwordController.text;
// Login login = login(email, sifre);
// girisYap.girisYap(context);
},
child: const Text("SIGN IN"),
style: OutlinedButton.styleFrom(
primary: const Color(0xFF166FC0),
side: const BorderSide(color: Color(0xFF0FA9EA), width: 2),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)))),
),
],
)
),
);
}
}
TextField widget
class InputAlan extends StatefulWidget {
const InputAlan({
Key? key,
required this.fieldType,
required this.textEditingController,
}) : super(key: key);
final Field fieldType;
final TextEditingController textEditingController;
#override
State<InputAlan> createState() => _InputAlanState();
}
class _InputAlanState extends State<InputAlan> {
#override
Widget build(BuildContext context) {
final isMailField = widget.fieldType == Field.mail;
return Padding(
padding: const EdgeInsets.only(top: 50, left: 20, right: 20),
child: TextFormField(
controller: widget.textEditingController,
autofocus: widget.fieldType == Field.mail,
obscureText: !isMailField,
decoration: InputDecoration(
labelText: isMailField ? "E - Mail" : "Password",
hintText: isMailField ? "E-Mail" : "Password",
prefixIcon:
Icon(isMailField ? Icons.email_outlined : Icons.password_sharp),
suffixIcon: const Icon(Icons.lock),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
)),
),
);
}
}
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
});
});
}
How can I update the PinInput Boxes with input from the on-screen keyboard? From what I understand, whenever there's a state change, the widget will be rebuild. Hence, from below, what I did was updating the text whenever the on-screen keyboard detects tap. Then since the state is changed, I assumed it will rebuild all the widget which include the PinInput widget, and this is true since I tested the text whenever there's changes. I then did _pinPutController.text = text; to change the input of PinInput, however it is not working.
When I hardcode _pinPutController.text = '123', it works. So the problem is that it is not rebuilding. Am I understanding this correctly? How can I achieve what I wanted?
import 'package:flutter/material.dart';
import 'package:numeric_keyboard/numeric_keyboard.dart';
import 'package:pinput/pin_put/pin_put.dart';
import '../../../../constants.dart';
import '../../../../size_config.dart';
class InputForm extends StatefulWidget {
#override
_InputFormState createState() => _InputFormState();
}
class _InputFormState extends State<InputForm> {
String text = '';
#override
Widget build(BuildContext context) {
return Column(
children: [
PinInput(text: text),
NumericKeyboard(
onKeyboardTap: (value) {
setState(() {
text += value;
});
},
textColor: Colors.red,
rightButtonFn: () {
setState(() {
text = text.substring(0, text.length - 1);
});
},
rightIcon: Icon(
Icons.backspace,
color: Colors.red,
),
mainAxisAlignment: MainAxisAlignment.spaceEvenly),
],
);
}
}
class PinInput extends StatelessWidget {
const PinInput({
Key key,
this.text,
}) : super(key: key);
final String text;
#override
Widget build(BuildContext context) {
final size = getProportionateScreenHeight(60);
final TextEditingController _pinPutController = TextEditingController();
final FocusNode _pinPutFocusNode = FocusNode();
_pinPutFocusNode.unfocus();
print(text);
_pinPutController.text = text;
return PinPut(
fieldsCount: 4,
onSubmit: (String pin) => {},
focusNode: _pinPutFocusNode,
controller: _pinPutController,
preFilledWidget: Align(
alignment: Alignment.bottomCenter,
child: Divider(
color: kPrimaryColor,
thickness: 2.5,
indent: 7.5,
endIndent: 7.5,
),
),
textStyle: TextStyle(
fontSize: getProportionateScreenHeight(24),
),
eachFieldPadding: EdgeInsets.all(
getProportionateScreenHeight(10),
),
eachFieldMargin: EdgeInsets.all(
getProportionateScreenWidth(5),
),
eachFieldHeight: size,
eachFieldWidth: size,
submittedFieldDecoration: boxDecoration(),
selectedFieldDecoration: boxDecoration(),
followingFieldDecoration: boxDecoration(),
inputDecoration: InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
counterText: '',
),
withCursor: true,
pinAnimationType: PinAnimationType.scale,
animationDuration: kAnimationDuration,
);
}
BoxDecoration boxDecoration() {
return BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(10),
),
);
}
}
The problem is that you recreate a new TextEditingController at each rebuild of your PinInput Widget. However, if you check the PinPutState of the pinput package, it keeps a reference to the first TextEditingController you provide in its initState method:
#override
void initState() {
_controller = widget.controller ?? TextEditingController();
[...]
}
So, you have to keep the same TextEditingController all the way.
The easiest way to fix this would be to raise the TextEditingController to the State of InputForm. Instead of a String text, just use a Controller:
class InputForm extends StatefulWidget {
#override
_InputFormState createState() => _InputFormState();
}
class _InputFormState extends State<InputForm> {
TextEditingController _controller = TextEditingController(text: '');
#override
Widget build(BuildContext context) {
return Column(
children: [
PinInput(controller: _controller),
NumericKeyboard(
onKeyboardTap: (value) => _controller.text += value,
textColor: Colors.red,
rightButtonFn: () => _controller.text =
_controller.text.substring(0, _controller.text.length - 1),
rightIcon: Icon(Icons.backspace, color: Colors.red),
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
],
);
}
}
Note: Since you use a TextEditingController instead of a String, you can get rid of all your setState methods.
Full source code:
import 'package:flutter/material.dart';
import 'package:numeric_keyboard/numeric_keyboard.dart';
import 'package:pinput/pin_put/pin_put.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
);
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: InputForm()),
);
}
}
class InputForm extends StatefulWidget {
#override
_InputFormState createState() => _InputFormState();
}
class _InputFormState extends State<InputForm> {
TextEditingController _controller = TextEditingController(text: '');
#override
Widget build(BuildContext context) {
return Column(
children: [
PinInput(controller: _controller),
NumericKeyboard(
onKeyboardTap: (value) => _controller.text += value,
textColor: Colors.red,
rightButtonFn: () => _controller.text =
_controller.text.substring(0, _controller.text.length - 1),
rightIcon: Icon(Icons.backspace, color: Colors.red),
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
],
);
}
}
class PinInput extends StatelessWidget {
const PinInput({
Key key,
this.controller,
}) : super(key: key);
final TextEditingController controller;
#override
Widget build(BuildContext context) {
final size = 60.0;
final FocusNode _pinPutFocusNode = FocusNode();
_pinPutFocusNode.unfocus();
return PinPut(
fieldsCount: 4,
onSubmit: (String pin) => {},
focusNode: _pinPutFocusNode,
controller: controller,
preFilledWidget: Align(
alignment: Alignment.bottomCenter,
child: Divider(
color: Theme.of(context).primaryColor,
thickness: 2.5,
indent: 7.5,
endIndent: 7.5,
),
),
textStyle: TextStyle(
fontSize: 24,
),
eachFieldPadding: EdgeInsets.all(
10,
),
eachFieldMargin: EdgeInsets.all(
5,
),
eachFieldHeight: size,
eachFieldWidth: size,
submittedFieldDecoration: boxDecoration(),
selectedFieldDecoration: boxDecoration(),
followingFieldDecoration: boxDecoration(),
inputDecoration: InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
counterText: '',
),
withCursor: true,
pinAnimationType: PinAnimationType.scale,
animationDuration: Duration(milliseconds: 500),
);
}
BoxDecoration boxDecoration() {
return BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(
10,
),
);
}
}
UPDATE: How to hide the Keyboard...
...while keeping the focus blinking cursor
1. disable the focus on your PinPut fields:
For this, I used a class described here:
class AlwaysDisabledFocusNode extends FocusNode {
#override
bool get hasFocus => false;
}
...as the focusNode of the PinPut:
class PinInput extends StatelessWidget {
[...]
#override
Widget build(BuildContext context) {
final size = 60.0;
final FocusNode _pinPutFocusNode = AlwaysDisabledFocusNode();
// _pinPutFocusNode.unfocus();
return PinPut(
[...]
focusNode: _pinPutFocusNode,
[...]
);
}
}
So, now, the PinPut never gets the focus. The Soft Keyboard is not shown but, hey!, we lost the blinking cursor!
No worries, we'll keep it always on programmatically.
2. Keep the blinking cursor always on
For this, though, we'll have to change the code of the pinput package.
Currently, in PinPutState, the blinking cursor is shown on the next field if withCursor is set to true and the PinPut has the focus. Instead, we will always show the blinking cursor if withCursoris set to true:
if (widget.withCursor /* && _focusNode!.hasFocus */ && index == pin.length) {
return _buildCursor();
}
Voilà ! Does it work for you?
This has been mentioned on PinPut GitHub Issue Tracker [ref] about disabling the device keyboard when using a custom keyboard.
I have a form where i want the clear button to appear on the right side of the textfield only when user start entering data and disappear if user delete all the data he input in the textfield. currently, i was able to add the clear button but it is there always.
see my code below
this is the code for my textiput
import 'package:flutter/material.dart';
import 'package:finsec/utils/hex_color.dart';
class CustomTextField extends StatelessWidget {
CustomTextField({
this.textInputType,
this.textController ,
this.errorMessage,
this.labelText,
});
TextInputType textInputType;
TextEditingController textController;
String errorMessage, labelText;
#override
Widget build(BuildContext context) {
bool isError = false;
return Container(
child: TextFormField(
keyboardType: textInputType,
style: Theme
.of(context)
.textTheme
.title,
controller: textController,
validator: (String value) {
if (value.isEmpty) {
return errorMessage;
}
},
decoration: InputDecoration(
suffixIcon: IconButton(
onPressed: (){
textController.clear();
},
icon: Icon(
Icons.clear,
color: Colors.grey,
),
),
labelStyle: TextStyle(
color: Colors.grey,
fontSize: 16.0
),
contentPadding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0), //size of textfield
errorStyle: TextStyle(
color: Colors.red,
fontSize: 15.0
),
border: OutlineInputBorder(
borderSide: BorderSide(width:5.0),
borderRadius: BorderRadius.circular(5.0)
)
)
),
);
}
}
here is my code for the form
import 'package:flutter/material.dart';
import 'package:finsec/widget/row_text_input.dart';
import 'package:finsec/widget/text_form_field.dart';
import 'package:finsec/widget/save_button.dart';
import 'package:finsec/utils/strings.dart';
import 'package:finsec/utils/dimens.dart';
import 'package:finsec/utils/colors.dart';
import 'package:finsec/widget/column_text_input.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Simple Interest Calculator App',
home: ThirdFragment(),
theme: ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.indigo,
accentColor: Colors.indigoAccent),
));
}
class ThirdFragment extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _ThirdFragmentState();
}
}
class _ThirdFragmentState extends State<ThirdFragment> {
var _formKey = GlobalKey<FormState>();
var _currencies = ['Rupees', 'Dollars', 'Pounds'];
final double _minimumPadding = 5.0;
var _currentItemSelected = '';
#override
void initState() {
super.initState();
_currentItemSelected = _currencies[0];
// principalController.addListener(onChange);
}
TextEditingController amountController = TextEditingController();
TextEditingController frequencyController = TextEditingController();
TextEditingController datePaidController = TextEditingController();
TextEditingController categoryController = TextEditingController();
TextEditingController depositToController = TextEditingController();
TextEditingController descriptionController = TextEditingController();
var displayResult = '';
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
return Scaffold(
appBar: AppBar(
title: Text('Simple Interest Calculator'),
),
body: Form(
key: _formKey,
onChanged: ,
child: SingleChildScrollView(
child: Column (children: [
Padding(
padding: EdgeInsets.only(top: 10.0, bottom: 5.0, left: 15.0, right: 15.0),
child: CustomTextField(textInputType:TextInputType.number,
textController: amountController,
errorMessage:'Enter Income Amount',
labelText:'Income Amount for testing'),
),
RowTextInput(inputName: 'Frequency:',
textInputType: TextInputType.number,
textController: frequencyController,
errorMessage: 'Choose Income Frequency',
labelText: 'Income Amount for testing'
),
RowTextInput(inputName: 'Date Paid:',
textInputType: TextInputType.number,
textController: datePaidController,
errorMessage: 'Pick Income Payment Date',
labelText: 'Income Amount for testing'
),
RowTextInput(inputName: 'Category:',
textInputType: TextInputType.number,
textController: categoryController,
errorMessage: 'Enter Income Category',
labelText: 'Income Amount for testing'
),
RowTextInput(inputName: 'Deposit To:',
textInputType: TextInputType.number,
textController: depositToController,
errorMessage: 'Choose Bank Acct Where Income Is Deposited',
labelText: 'Income Amount for testing'
),
RowTextInput(inputName: 'Description:',
textInputType: TextInputType.number,
textController: descriptionController,
errorMessage: 'Please enter principal amount',
labelText: 'Income Amount for testing'
),
SizedBox(height: 20),
//saveButton()
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
MaterialButton(
height: margin_40dp,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(margin_5dp)),
minWidth: (MediaQuery.of(context).size.width * .9) / 2,
color: Theme.of(context).primaryColor,
textColor: white,
child: new Text(save),
onPressed: () => {
setState(() {
if (_formKey.currentState.validate()) {
// amountController.text.isEmpty ? amountController.text='Value require' : amountController.text='';
//this.displayResult = _calculateTotalReturns();
}
})
},
splashColor: blueGrey,
),
MaterialButton(
height: margin_40dp,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(margin_5dp)),
minWidth: (MediaQuery.of(context).size.width * .9) / 2,
color: Theme.of(context).primaryColor,
textColor: white,
child: new Text(save_and_continue),
onPressed: () => {},
splashColor: blueGrey,
)
])
]
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:finsec/widget/text_form_field.dart';
class RowTextInput extends StatelessWidget {
RowTextInput({
this.inputName,
this.textInputType,
this.textController ,
this.errorMessage,
this.labelText,
// this.hint,
// this.height,
// this.padding,
// this.headerRadius,
});
TextInputType textInputType;
TextEditingController textController;
String inputName, errorMessage, labelText;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(
top: 5.0, bottom: 5.0, left: 15.0, right: 15.0),
child: Row(children: [
Expanded(
child: Text(this.inputName, maxLines: 1,)
),
Expanded(
flex: 3,
child: CustomTextField(textInputType:TextInputType.number,
textController: this.textController,
errorMessage: this.errorMessage
),
),
]),
);
}
}
i am expecting the clear (x button) to disappear when textfield is empty and appear when user type or select a value from dropdown etc. can someone help? thanks in advance
You can make use of Dart's conditional expression to check if textfield is empty then don't show X button else show it. For ex, the textController is used to retrieve value of textfield. You can check if the value retrieved is greater than 0 then show X button, else show empty container().
textController.text.length > 0 ? IconButton(icon: Icon(Icons.clear), onPressed: () {} : Container()
Note: You will need to adjust above line w.r.t your code as applicable.
Hope this helps and resolves your issue.