How to make two text fields that show related content, and editable? - flutter

I'am trying to do a mobile app which is about crypto currencies.
I want to make two TextFields like USDT and BTC, And they are supposed to work like:
Let me say that BTC is equal to 15$,
And USDT is equal to 1$,
Now those text fields should be editable. so if I write 1 on BTC textfield, USDT textfield should me edited as 15.
Also, when I write 30 on USDT textfield, BTC field should become 2. Moreover, while in this position, if I delete 0 from the usdt field, BTC should updated with "0.something" directly.
How can I do that?
Thanks for the replies !
I managed to do something like USDT is input, and BTC is output. However, I want to make them both input and output. Below are my classes, widgets and codes.
import 'package:cryptx/Constants/app_colors.dart';
import 'package:cryptx/Providers/basic_providers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class USDTInput extends ConsumerWidget {
const USDTInput({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: TextField(
decoration: InputDecoration(
icon: SizedBox(
height: 30,
child: Image.network(
"https://assets.coingecko.com/coins/images/325/small/Tether.png?1668148663")),
hintText: "USDT",
border: InputBorder.none,
),
onChanged: (value) {
ref
.read(usdProvider.notifier)
.update((state) => value != "" ? num.parse(value) : 0);
},
autocorrect: false,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
),
);
}
}
import 'package:cryptx/Objects/coin.dart';
import 'package:cryptx/Providers/basic_providers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class CoinOutput extends ConsumerWidget {
const CoinOutput({super.key});
#override
Widget build(BuildContext context, WidgetRef ref) {
Coin coin = ref.watch(coinDetailProvider) as Coin;
num usd = ref.watch(usdProvider);
num amount = usd != 0 ? usd / coin.current_price : 0;
//return Text(amount.toString());
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: TextField(
decoration: InputDecoration(
icon: SizedBox(height: 30, child: Image.network(coin.image)),
hintText: "Coin",
border: InputBorder.none,
),
controller:
TextEditingController(text: "$amount ${coin.symbol.toUpperCase()}"),
readOnly: true,
autocorrect: false,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
onChanged: (value) {
ref.watch(coin_usdProvider.notifier).update((state) =>
value != "" ? num.parse(value) / coin.current_price : 0);
},
),
);
}
}

I think the easiest solution would be to create an outside function which can relate/update these two values.
for example:
void updateValues(float BTC, var USDT)
And then use a FocusNode (see also stackoverflow_question) to detect which of the TextFields is/was selected. That was you know which value is the new one and which one to change.
In this solution you should call this function in an onChanged property of the widgets.
FocusNode can be used either to call something when its focus is changed or to check if something has a focus. So using this class you can solve it in a couple different ways.

Try this example out:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final btcTextController = TextEditingController();
final usdtTextController = TextEditingController();
final btcFocusNode = FocusNode();
final usdtFocusNode = FocusNode();
double btcValue = 15;
double usdTValue = 1;
String curSelection = "";
#override
void initState() {
btcTextController.addListener(calcBTC);
usdtTextController.addListener(calcUSDT);
super.initState();
}
void calcBTC() {
if (btcFocusNode.hasFocus) {
usdtTextController.clear();
if (btcTextController.text.isNotEmpty &&
double.tryParse(btcTextController.text) != null) {
setState(() {
usdtTextController.text =
(double.parse(btcTextController.text) * (btcValue / usdTValue))
.toString();
});
}
}
}
void calcUSDT() {
if (usdtFocusNode.hasFocus) {
btcTextController.clear();
if (usdtTextController.text.isNotEmpty &&
double.tryParse(usdtTextController.text) != null) {
setState(() {
btcTextController.text =
(double.parse(usdtTextController.text) * (usdTValue / btcValue))
.toString();
});
}
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Card(
color: Colors.white,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
elevation: 4,
child: Container(
margin: const EdgeInsets.all(10),
width: 300,
height: 300,
child: Column(
children: [
Expanded(
child: TextField(
style: const TextStyle(color: Colors.black),
controller: btcTextController,
focusNode: btcFocusNode,
decoration: InputDecoration(
filled: true,
fillColor: Colors.blue.shade100,
labelText: 'BTC',
labelStyle: const TextStyle(color: Colors.pink),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
)),
),
),
Expanded(
child: TextField(
style: const TextStyle(color: Colors.black),
controller: usdtTextController,
focusNode: usdtFocusNode,
decoration: InputDecoration(
filled: true,
fillColor: Colors.blue.shade100,
labelText: 'USDT',
labelStyle: const TextStyle(color: Colors.pink),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
)),
)),
],
),
),
),
),
),
);
}
}
You will deffo need to add more validation etc. Also you can possibly use one single function to do calculations and use the focusNodes to decide which side needs to be calculated against which.

Related

passing a widget that has setState to another page without stateful/stateless widget

Is Any Way How to pass a widget function to another page that is without any stateless/stateful? The file only includes widgets such as textfields, buttons and etc. I am trying not to cluster every fields in one page. Any helps/ideas would be appreciated!
Main.dart
class MainPage extends StatefulWidget {
const MainPage({super.key});
#override
State<Main Page> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
// bool for toggling password
bool isSecuredPasswordField = true;
#override
Widget build(BuildContext context) {
return Container();
}
// widget function that I need to pass on widget_fields.dart
Widget togglePassword() {
return IconButton(
onPressed: () {
setState(() {
isSecuredPasswordField = !isSecuredPasswordField;
});
},
icon: isSecuredPasswordField
? const Icon(Icons.visibility)
: const Icon(Icons.visibility_off),
);
}
}
widget_fields.dart
Widget userPasswordField(_passwordUserCtrlr) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: TextFormField(
obscureText: true,
controller: _passwordUserCtrlr,
keyboardType: TextInputType.visiblePassword,
decoration: InputDecoration(
isDense: true,
suffixIcon: togglePassword(), //<-- I wanna call that function here
prefixIcon: const Icon(Icons.lock),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Color(0xFFCECECE)),
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFFCECECE)),
),
hintText: 'Password',
hintStyle: const TextStyle(
fontFamily: 'Poppins',
fontSize: 14,
),
fillColor: const Color(0xFFFEFEFE),
filled: true,
),
validator: (value) {
if (value!.isEmpty) {
return "Please enter your password.";
} else if (value.length < 8) {
return "Password should be min. 8 characters.";
} else {
return null;
}
},
),
);
}
You can pass functions like any other variable. I made a full working example that's different than yours to show a more minimal example but you can apply the same logic for your code
main.dart
import 'package:flutter/material.dart';
import 'column.dart';
void main() {
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
Widget returnSomeText() {
return const Text("test");
}
#override
Widget build(BuildContext context) {
return Scaffold(body: createColumn(returnSomeText));
}
}
column.dart
import 'package:flutter/material.dart';
Widget createColumn(Function widgetFunction) {
return Column(
children: [widgetFunction(), widgetFunction()],
);
}
As you can see the togglePassword from your code corresponds to returnSomeText in mine. and userPasswordField is like createColumn. But it must be said that it's not recommended to use helper functions like createColumn here but to turn it into a StatelessWidget, like this for example:
import 'package:flutter/material.dart';
class CreateColumn extends StatelessWidget {
final Function widgetFunction;
const CreateColumn({Key? key, required this.widgetFunction}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [widgetFunction(), widgetFunction()],
);
}
}
And then in main.dart:
return Scaffold(body: CreateColumn(widgetFunction: returnSomeText));
See also this YouTube video: Widgets vs helper methods
This is Example that how you call Widget in another class:
class MainApge extends StatefulWidget {
const MainApge({Key? key}) : super(key: key);
#override
State<MainApge> createState() => _MainApgeState();
}
class _MainApgeState extends State<MainApge> {
#override
Widget build(BuildContext context) {
return Column(
children: [
ContainerTextFields.customsTextField(
"User Name",
'enter name',
userNameController,
),
],
);
}
}
This is Custom Widget Class:
class ContainerTextFields {
static Widget customsTextField(
String label, String cusHintText, TextEditingController _controller) {
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: EdgeInsets.only(
left: SizeConfig.screenHeight! * 0.05,
top: SizeConfig.screenHeight! * 0.03),
child: Text(
label,
style: AppStyle.kUnSyncedDialogeText.copyWith(
color: AppColors.kTextFieldLabelColorGrey,
fontWeight: FontWeight.bold),
)),
Padding(
padding: EdgeInsets.only(
top: SizeConfig.screenHeight! * 0.02,
left: SizeConfig.screenHeight! * 0.042,
right: SizeConfig.screenWidth! * 0.042),
child: SingleChildScrollView(
child: Container(
height: SizeConfig.screenHeight! * 0.065,
child: TextFormField(
controller: _controller,
decoration: InputDecoration(
hintText: cusHintText,
hintStyle: TextStyle(
color: AppColors.kLoginPopUpColor,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
),
),
)
]);
}
}
You can pass the widget as parameter to child widget:
class MyTextField extends StatelessWidget {
const MyTextField({Key? key,
this.togglePassword,
this.passwordUserCtrlr
})
: super(key: key);
final Widget? togglePassword;
final TextEditingController? passwordUserCtrlr;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: TextFormField(
obscureText: true,
controller: passwordUserCtrlr,
keyboardType: TextInputType.visiblePassword,
decoration: InputDecoration(
isDense: true,
suffixIcon: togglePassword, //<-- I wanna call that function here
prefixIcon: const Icon(Icons.lock),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Color(0xFFCECECE)),
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFFCECECE)),
),
hintText: 'Password',
hintStyle: const TextStyle(
fontFamily: 'Poppins',
fontSize: 14,
),
fillColor: const Color(0xFFFEFEFE),
filled: true,
),
validator: (value) {
if (value!.isEmpty) {
return "Please enter your password.";
} else if (value.length < 8) {
return "Password should be min. 8 characters.";
} else {
return null;
}
},
),
);
}
}
And can easily call from main widget:
class MainPage extends StatefulWidget {
const MainPage({super.key});
#override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
// bool for toggling password
bool isSecuredPasswordField = true;
TextEditingController? passwordUserCtrlr = TextEditingController();
#override
Widget build(BuildContext context) {
return MyTextField(
togglePassword: togglePassword(),
passwordUserCtrlr: passwordUserCtrlr,
);
}
// widget function that I need to pass on widget_fields.dart
Widget togglePassword() {
return IconButton(
onPressed: () {
setState(() {
isSecuredPasswordField = !isSecuredPasswordField;
});
},
icon: isSecuredPasswordField
? const Icon(Icons.visibility)
: const Icon(Icons.visibility_off),
);
}
}
You can create class like GlobalWidget for example, like this:
class GlobalWidget {
// widget function that I need to pass on widget_fields.dart
Widget togglePassword(Function()? onPressed, bool value) {
return IconButton(
onPressed: onPressed,
icon: value
? const Icon(Icons.visibility)
: const Icon(Icons.visibility_off),
);
}
}
And You can call the Widget like that :
GlobalWidget().togglePassword(() => setState(() {
isSecuredPasswordField = !isSecuredPasswordField;
}), isSecuredPasswordField)
What you are trying to do is impossible in the Flutter framework. You cannot call methods belonging to other widgets
Also, it is discouraged to use function to return widgets as this impacts the framework's ability to optimize the build process.
One possible solution is to package your complete password entry in a set of custom (statefull) widgets. You can collect those into a single source file if you like. Be sure to create a class for every widget.

Working With Seperate Files in Flutter/Dart

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)),
)),
),
);
}
}

how to make clear button appears when text is enter in TextFormField in flutter

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.

How can I change the state of a button from another Stateful widget or class?

I've created a FlatButton in one of my Widget Screens, whose State i want to be managed by another Stateful widget in the same screen. It is a textfield , which when it starts editing , I want to enable the button. How can I do this? I made a function to toggle the boolean value of the button, but when i try to access this function from my Stateful widget class it gives the error, 'Instance member can't be accessed using static access'. How can I resolve this issue ?
My main Screen code
import 'package:flutter/material.dart';
import 'package:flutter_convertor/ItemBought.dart';
class task extends StatefulWidget{
#override
taskState createState() => new taskState();
}
class taskState extends State<task> {
int current_step = 0;
bool isButtonDisabled;
#override void initState() {
super.initState();
isButtonDisabled = false;
}
formReady(){
setState(() {
isButtonDisabled = !isButtonDisabled ;
});
}
#override
Widget build(BuildContext context) {
Column taskScreen = Column(
children: <Widget>[
ItemBought(), //STATEFUL widget which contains another Stateful widget addImage()
//some other implementation
FlatButton(
color: Colors.red,
textColor: Colors.black,
shape: new RoundedRectangleBorder(borderRadius: new BorderRadius.circular(20.0)),
disabledColor: Color(0XFFf9c3c1),
disabledTextColor: Colors.white,
padding: EdgeInsets.all(8.0),
splashColor: Colors.red[400],
onPressed: isButtonDisabled ? null : _completePage
,
child: Text(
"Completed",
style: TextStyle(color: Colors.white, fontSize: 15.0, fontWeight: FontWeight.bold),
),
)
,
],
)
]);
return taskScreen;
}
}
Widget from which i am trying to change the state of the FlatButton:
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:flutter_convertor/task.dart';
class addImage extends StatefulWidget{
#override
_addImageState createState() => _addImageState();
}
class _addImageState extends State<addImage> {
Column itemDetails = Column(
//some implementation
);
Column OPObservations = Column(
children: <Widget>[
//otherlayout widgets
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: TextField(
onChanged: taskState.formReady(), //GIVES ERROR
maxLines: 6 ,
style: new TextStyle(
fontSize: 13.0,
),
controller: TextEditingController(),
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: "Enter the details",
labelStyle: TextStyle(color: Colors.grey[400], fontSize: 13.0),
contentPadding: EdgeInsets.only(top:8.0, bottom: 8.0,left: 10.0),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey[400]),
borderRadius: BorderRadius.all(Radius.circular(8.0))),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red),
)
)
),
),
],
);
#override
Widget build(BuildContext context) {
return Container(
child: _image == null ? Column (
//some implementation
)
: Column(
children: <Widget>[
itemDetails,
OPObservations,
]
)
);
}
}
Didn't read your code (sorry) but according to your question there are two possible ways:
1) you could follow the lift-state-up principle and store the state of the button in the parent widget of both other components.
2) You implement a (public) method changing the state of the button and call it from the other widget. you could do this by accessing the method by asigning the button-widget a GlobalKey and then do something like this buttonKey.currentState.changeStateMethod(newState);.
Hope one of the method help :)

Is there a way which helps the keyboard focus correctly on the textformfield

I write an android app with flutter. As a part of my code I created a user page to let the user to update their information such as name surname or something like that.
It is working but when I clicked the page I am getting few errors.
1 is I/ple.flutter_ap(18747): The ClassLoaderContext is a special shared library.
2nd is W/ple.flutter_ap(18747): Accessing hidden field Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList; (light greylist, reflection)
And the other problem is The keyboard is not focusing on the textfield. When I clicked the textfield the keyborad is Opening and closing immediately. When I clicked again it shows up and again closing immediately.
I tried autofocus: true but this time it tried to focus it self. It is opended and closed 5 times but at last it focused. But that shouldnt be happen.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Screen1 extends StatefulWidget {
#override
_Screen1State createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
var _AdContr = TextEditingController();
var _SoyadContr = TextEditingController();
final _NicknameContr = TextEditingController();
final _getContr = TextEditingController();
final _myUpdateContr = TextEditingController();
var _transactionListener;
#override
void dispose() {
// Clean up controllers when disposed
_AdContr.dispose();
_SoyadContr.dispose();
_NicknameContr.dispose();
_getContr.dispose();
_myUpdateContr.dispose();
// Cancel transaction listener subscription
_transactionListener.cancel();
super.dispose();
}
void clickUpdate(_formKey1, _formKey2) async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
String uid = user.uid.toString();
await Firestore.instance
.collection('kitaplar')
.document(uid)
.updateData({'adi': _formKey1, 'Soyadi': _formKey2});
Navigator.pop(context);
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Retrieve Text Input'),
),
body: new Container(
padding: EdgeInsets.only(top: 20.0, left: 10.0, right: 10.0),
child: FutureBuilder(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context,
AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.connectionState != ConnectionState.done)
return Container();
return StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance.collection('kitaplar')
.document(snapshot.data.uid)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) return Container();
var userDocument = snapshot.data;
var contentadi = userDocument["adi"].toString();
var contentsoyadi = userDocument["Soyadi"].toString();
return Column(
children: <Widget>[
TextFormField(
controller: _AdContr = new TextEditingController(text: contentadi == null ? "" : contentadi),
//controller: _AdContr,
//initialValue: userDocument["adi"].toString(),
decoration: new InputDecoration(
labelText: 'Adınız',
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(),
),
//fillColor: Colors.green
),
),
SizedBox(height: 20),
TextFormField(
controller: _SoyadContr = new TextEditingController(text: contentsoyadi == null ? "" : contentsoyadi),
//controller: _AdContr,
decoration: new InputDecoration(
labelText: 'Soyadınız',
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(),
),
//fillColor: Colors.green
),
),
RaisedButton(
color: Colors.orange,
textColor: Colors.white,
splashColor: Colors.orangeAccent,
child: const Text('Update'),
onPressed: () {
clickUpdate(_AdContr.text, _SoyadContr.text);
},
),
],
);
},
);
})
)
);
}
}
How do I solve this problem?
To foucs on next text input field you have to use "FocusNode();" such as below:
In the "TextFormField(" we can use this method to focus:
onFieldSubmitted: (v){
FocusScope.of(context).requestFocus(focus);
},
Also to set different options for text input field such as next and done options in keyboard, you can use below method:
1) For next option: "textInputAction: TextInputAction.next,"
2) For done option: "textInputAction: TextInputAction.done,"
Below is the full example to auto focus on next text input field:
class MyApp extends State<MyLoginForm> {
final _formKey = GlobalKey<FormState>();
final focus = FocusNode();
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Center(
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 30, top: 65.0, right: 30, bottom: 0),
child:
TextFormField(
textInputAction: TextInputAction.next,
decoration: new InputDecoration(hintText: 'Enter username', contentPadding: EdgeInsets.all(8.0)),
style: new TextStyle(fontSize: 18),
onFieldSubmitted: (v){
FocusScope.of(context).requestFocus(focus);
},
),
),
Padding(
padding: const EdgeInsets.only(left: 30, top: 30.0, right: 30, bottom: 0),
child:
TextFormField(
focusNode: focus,
textInputAction: TextInputAction.done,
decoration: new InputDecoration(hintText: 'Enter password', contentPadding: EdgeInsets.all(8.0)),
style: new TextStyle(fontSize: 18),
onFieldSubmitted: (v){
FocusScope.of(context).requestFocus(focus);
},
),
),
],
),
),
),
);
}
}
Problem is you are setting the text in TextFormField when keyboard opens with the TextEditingController. It means
you are assigning a value every time in TextEditingController so when keyboard opens, "TextEditingController" will
fire and it will try to check your condition and set the default value in your TextFormField and then keyboard gets
closed as normal behaviour.
So to solve this do as below:
First of all initialize your "TextEditingController" with "new" keyboard as below:
var _AdContr = new TextEditingController();
var _SoyadContr = new TextEditingController();
final _NicknameContr = new TextEditingController();
final _getContr = new TextEditingController();
final _myUpdateContr = new TextEditingController();
Then try to set default text for "TextFormField" after this two lines:
var contentadi = userDocument["adi"].toString();
var contentsoyadi = userDocument["Soyadi"].toString();
_AdContr.text = (contentadi == null ? "" : contentadi);
_SoyadContr.text = (contentsoyadi == null ? "" : contentsoyadi);
Then change your "TextFormField" as below and try to save those value in your variables in "onSubmitted" method:
return Column(
children: <Widget>[
TextFormField(
controller: _AdContr,
onSubmitted: (String str){
setState(() {
contentadi = str;
_AdContr.text = contentadi;
});
},
decoration: new InputDecoration(
labelText: 'Adınız',
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(),
),
//fillColor: Colors.green
),
),
SizedBox(height: 20),
TextFormField(
controller: _SoyadContr,
onSubmitted: (String str){
setState(() {
contentsoyadi = str;
_SoyadContr.text = contentsoyadi;
});
},
decoration: new InputDecoration(
labelText: 'Soyadınız',
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(),
),
//fillColor: Colors.green
),
),
RaisedButton(
color: Colors.orange,
textColor: Colors.white,
splashColor: Colors.orangeAccent,
child: const Text('Update'),
onPressed: () {
clickUpdate(_AdContr.text, _SoyadContr.text);
},
),
],
);
If above solution not work then try to use StreamBuilder() instead of FutureBuilder(). it will work and focuse without any problem.