Reputation: 255
I am developing a calculator type flutter application. I want to
This is the main calculator class
class Calculator extends StatefulWidget {
@override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
double soldPrice=0.00;
void printSoldPrice(){
print(soldPrice);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: BgColor ,
bottomNavigationBar: Container(
decoration: BoxDecoration(
borderRadius:BorderRadius.only(topLeft: Radius.circular(10), topRight:Radius.circular(10) ),
color:YellowBg,
),
alignment: Alignment.center,
height: 50,
child: Text('RESET',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
letterSpacing: 5,
),
),
),
body: SafeArea(
child: Column(
children: <Widget>[
SizedBox(height:10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
EcalLogo(logoSize: 30,),
],
),
SizedBox(height:10),
Padding(
padding:EdgeInsets.symmetric(horizontal:10.0),
child:FractionallySizedBox(
widthFactor: 0.9,
child: Container(
height:1.0,
width:130.0,
color:Colors.white,),
),),
SizedBox(height: 10,),
Expanded(
child:ListView(
children: <Widget>[
TextFieldContainer1(
title: 'SOLD PRICE',
tagLine: "SALE PRICE WITOHUT SHIPPING",
icon: Icons.check_circle,
),
],
))
],
),
)
);
}
}
This is the child TextFieldContainer1 class
class TextFieldContainer1 extends StatefulWidget {
final String title;
final String tagLine;
final IconData icon;
TextFieldContainer1({this.title,this.tagLine,this.icon});
@override
_TextFieldContainer1State createState() => _TextFieldContainer1State();
}
class _TextFieldContainer1State extends State<TextFieldContainer1> {
final controller1 = TextEditingController();
@override
Widget build(BuildContext context) {
return FractionallySizedBox(
widthFactor: 0.95,
child: Container(
padding: EdgeInsets.symmetric(horizontal:20, vertical:5),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: tileBackground,
),
height: 57,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:<Widget>[
Container(
child:Column(
children:<Widget>[
Row(
children:<Widget>[
Icon(widget.icon,
color: Colors.white,
size:27.5
),
SizedBox(width:5),
Text(widget.title,
style: TextStyle(
fontSize: 20,
color:Colors.white,
fontWeight: FontWeight.w500
),
)
]
),
Text(widget.tagLine,
style: TextStyle(
color:Color.fromRGBO(255, 255, 255, 0.5),
fontSize: 12
),
)
]
)
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15,vertical: 5),
decoration: BoxDecoration(
color: Color.fromRGBO(252, 205, 0, 0.2),
borderRadius: BorderRadius.all(Radius.circular(10)
)
),
height: 40,
width: 92,
child: TextField(
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 20
),
autofocus: false,
decoration:InputDecoration(
focusColor: YellowBg,
fillColor: YellowBg,
hoverColor: YellowBg,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: YellowBg),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: YellowBg),)
) ,
keyboardType: TextInputType.number,
controller: controller1,
),
)
],
),
),
);
}
}
I want to use the controller1 data (data from text field) in TextFieldContainer1 class to update the soldPrice variable in calculator class and simply print it when textField onChanged has triggered. How to do that?
Upvotes: 3
Views: 2971
Reputation: 631
It is pretty simple to create the custom class for textField. Below are the two steps to achieve this. First step is to create the stateful widget for text field.
RCTextField({
@required this.hintText,
@required this.labelText,
@required this.prefixIcon,
@required this.suffixIcon,
@required this.kType,
@required this.kAction,
@required this.validatorFunction,
@required this.onChange,
});
final String hintText;
final String labelText;
final String prefixIcon;
final String suffixIcon;
final TextInputType kType;
final TextInputAction kAction;
final Function validatorFunction;
final Function(String) onChange;
@override
_RCTextFieldState createState() => _RCTextFieldState();
}
class _RCTextFieldState extends State<RCTextField> {
FocusNode myFocusNode;
get validatorFunction => null;
get textFieldValue => null;
get onChange => null;
@override
void initState() {
super.initState();
myFocusNode = FocusNode();
myFocusNode.addListener(_onOnFocusNodeEvent);
}
_onOnFocusNodeEvent() {
setState(() {
// Re-renders
});
}
@override
void dispose() {
// Clean up the focus node when the Form is disposed.
myFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
// margin: EdgeInsets.fromLTRB(20, 20, 20, 0),
child: TextFormField(
onEditingComplete: () => FocusScope.of(context).nextFocus(),
textInputAction: widget.kAction,
cursorColor: Colors.black,
style: new TextStyle(color: _getInputTextColor()),
focusNode: myFocusNode,
validator: validatorFunction,
decoration: InputDecoration(
// focusColor: Colors.red,
// fillColor: Colors.blueGrey,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: kInactiveTextFieldColour),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: kActiveTextFieldColour),
),
border: UnderlineInputBorder(),
filled: false,
prefixIcon: Padding(
padding: EdgeInsets.all(14.0),
child: SvgPicture.asset(
'images/' + widget.prefixIcon + '.svg',
semanticsLabel: 'Acme Logo',
color: myFocusNode.hasFocus
? kActiveTextFieldColour
: kInactiveTextFieldColour,
),
),
hintText: widget.hintText,
labelText: widget.labelText,
labelStyle: TextStyle(
color: myFocusNode.hasFocus
? kActiveTextFieldColour
: kInactiveTextFieldColour),
),
keyboardType: widget.kType,
onChanged: widget.onChange,
),
);
}
Color _getInputTextColor() {
return myFocusNode.hasFocus ? Colors.black : Colors.black;
}
}
Below is the next end to last step to use this class.
RCTextField(
hintText: 'Enter your text',
labelText: 'Text',
prefixIcon: 'plus',
suffixIcon: null,
kType: TextInputType.visiblePassword,
kAction: TextInputAction.done,
onChange: (val) => setState(() {
print(val);
}),
),
Let me know if you find any trouble.
Upvotes: 2
Reputation: 2367
Full working code:
Add
final Function(String) onChange;
to TextFieldContainer1
Add
onChanged: widget.onChange,
to TextField (and remove Controller)
Add
onChange: (val) => setState(() {
soldPrice = double.parse(val);
print(val);
})
to TextFieldContainer1 call in Calculator.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(child: Calculator()),
),
);
}
}
Color BgColor = Colors.white;
Color YellowBg = Colors.yellow;
Color tileBackground = Colors.black;
class Calculator extends StatefulWidget {
@override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
double soldPrice=0.00;
void printSoldPrice(){
print(soldPrice);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: BgColor ,
bottomNavigationBar: Container(
decoration: BoxDecoration(
borderRadius:BorderRadius.only(topLeft: Radius.circular(10), topRight:Radius.circular(10) ),
color:YellowBg,
),
alignment: Alignment.center,
height: 50,
child: Text('RESET',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
letterSpacing: 5,
),
),
),
body: SafeArea(
child: Column(
children: <Widget>[
SizedBox(height:10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlutterLogo(size: 30,),
],
),
SizedBox(height:10),
Padding(
padding:EdgeInsets.symmetric(horizontal:10.0),
child:FractionallySizedBox(
widthFactor: 0.9,
child: Container(
height:1.0,
width:130.0,
color:Colors.white,),
),),
SizedBox(height: 10,),
Expanded(
child:ListView(
children: <Widget>[
TextFieldContainer1(
title: 'SOLD PRICE',
tagLine: "SALE PRICE WITOHUT SHIPPING",
icon: Icons.check_circle,
onChange: (val) => setState(() {
soldPrice = double.parse(val);
print(val);
})
),
],
)),
Text("$soldPrice")
],
),
)
);
}
}
class TextFieldContainer1 extends StatefulWidget {
final String title;
final String tagLine;
final IconData icon;
final Function(String) onChange;
TextFieldContainer1({this.title,this.tagLine,this.icon, this.onChange});
@override
_TextFieldContainer1State createState() => _TextFieldContainer1State();
}
class _TextFieldContainer1State extends State<TextFieldContainer1> {
@override
Widget build(BuildContext context) {
return FractionallySizedBox(
widthFactor: 0.95,
child: Container(
padding: EdgeInsets.symmetric(horizontal:20, vertical:5),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: tileBackground,
),
height: 57,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:<Widget>[
Container(
child:Column(
children:<Widget>[
Row(
children:<Widget>[
Icon(widget.icon,
color: Colors.white,
size:27.5
),
SizedBox(width:5),
Text(widget.title,
style: TextStyle(
fontSize: 20,
color:Colors.white,
fontWeight: FontWeight.w500
),
)
]
),
Text(widget.tagLine,
style: TextStyle(
color:Color.fromRGBO(255, 255, 255, 0.5),
fontSize: 12
),
)
]
)
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15,vertical: 5),
decoration: BoxDecoration(
color: Color.fromRGBO(252, 205, 0, 0.2),
borderRadius: BorderRadius.all(Radius.circular(10)
)
),
height: 40,
width: 92,
child: TextField(
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 20
),
autofocus: false,
decoration:InputDecoration(
focusColor: YellowBg,
fillColor: YellowBg,
hoverColor: YellowBg,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: YellowBg),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: YellowBg),)
) ,
keyboardType: TextInputType.number,
onChanged: widget.onChange,
),
)
],
),
),
);
}
}
Upvotes: 3
Reputation: 963
make the text field class constructor accept a function, then use that function in onChange
like below:
@override
_TextFieldContainer1State createState() => _TextFieldContainer1State();
}
class _TextFieldContainer1State extends State<TextFieldContainer1> {
final controller1 = TextEditingController();
final Function onChange;
@override
Widget build(BuildContext context) {
return FractionallySizedBox(
widthFactor: 0.95,
child: Container(
padding: EdgeInsets.symmetric(horizontal:20, vertical:5),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: tileBackground,
),
height: 57,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:<Widget>[
Container(
child:Column(
children:<Widget>[
Row(
children:<Widget>[
Icon(widget.icon,
color: Colors.white,
size:27.5
),
SizedBox(width:5),
Text(widget.title,
style: TextStyle(
fontSize: 20,
color:Colors.white,
fontWeight: FontWeight.w500
),
)
]
),
Text(widget.tagLine,
style: TextStyle(
color:Color.fromRGBO(255, 255, 255, 0.5),
fontSize: 12
),
)
]
)
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15,vertical: 5),
decoration: BoxDecoration(
color: Color.fromRGBO(252, 205, 0, 0.2),
borderRadius: BorderRadius.all(Radius.circular(10)
)
),
height: 40,
width: 92,
child: TextField(
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 20
),
onChange: widget.onChange,
autofocus: false,
decoration:InputDecoration(
focusColor: YellowBg,
fillColor: YellowBg,
hoverColor: YellowBg,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: YellowBg),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: YellowBg),)
) ,
keyboardType: TextInputType.number,
controller: controller1,
),
)
],
),
),
);
}
}
now when you use it in calculator class you use it like this:
TextFieldContainer1(
title: 'SOLD PRICE',
tagLine: "SALE PRICE WITOHUT SHIPPING",
icon: Icons.check_circle,
onChanga: (value) => print(value);
// now you have access to your text field value inside your calculator class
),
you may also want to make your text field class Stateless
as you are not using setState
anywhere.
Upvotes: 0