Working With Seperate Files in Flutter/Dart - flutter

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

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.

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

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.

How can I make FormBuilderTextField validators reusable?

So I am making a sign up page in Flutter. I'm gonna use this "flutter_form_builder" and "form_builder_validators" packages. I will make the textfields reusable to save time, and everything works, except the validators.
This is my reusable widget:
class MyFormBuilderTextField extends StatelessWidget {
final String name;
final Color inputTextColor;
final String labelText;
final Color labelColor;
final bool filled;
final Color fillColor;
final double borderRadius;
final Color enabledBorderColor;
final Color focusedBorderColor;
final FormFieldValidator<String> validators;
MyFormBuilderTextField({
required this.name,
this.inputTextColor = const Color(0xFFFFFFFF),
required this.labelText,
this.labelColor = Colors.white54,
this.filled = true,
this.fillColor = const Color(0xFF131313),
this.borderRadius = 10.0,
this.enabledBorderColor = Colors.white12,
this.focusedBorderColor = const Color(0xFFF57B3B),
required this.validators,
});
#override
Widget build(BuildContext context) {
return FormBuilderTextField(
name: name,
style: TextStyle(color: inputTextColor),
decoration: InputDecoration(
labelText: labelText,
labelStyle: TextStyle(color: labelColor),
filled: filled,
fillColor: fillColor,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadius),
borderSide: BorderSide(color: enabledBorderColor),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadius),
borderSide: BorderSide(color: focusedBorderColor),
),
),
validator:validators,
);
}
}
This is how I tried implementing it:
class MyFormBuilder extends StatefulWidget {
#override
State<MyFormBuilder> createState() => _MyFormBuilderState();
}
class _MyFormBuilderState extends State<MyFormBuilder> {
final _formKey = GlobalKey<FormBuilderState>();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF070707),
body: _buildContent(),
);
}
Widget _buildContent() {
return SingleChildScrollView(
padding: EdgeInsets.all(24.0),
child: FormBuilder(
key: _formKey,
child: Column(
children: <Widget>[
SizedBox(height: 30.0),
MyFormBuilderTextField(
name: 'password',
labelText: 'Password',
validators: [
FormBuilderValidators.min(8),
FormBuilderValidators.required(),
],
),
],
),
)
);
}
}
I am getting this error:
The argument type 'String? Function(String?)' can't be assigned to the parameter type 'List<String? Function(String?)>'.dartargument_type_not_assignable
How can I make the validators reusable?

Implementation Outlined text field Input with lable text in flutter application

i want to have a textFieldInput with border that has label inside the border like the image below. Thankyou in advance
TextField(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: "Label",
hintText: "Input Text",
contentPadding: EdgeInsets.fromLTRB(32, 16, 32, 16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
Result:
I think you want to achieve something like this.
Inactive
Active
Validation
You can achieve this design by using this widget.
class OutlineBorderTextFormField extends StatefulWidget {
FocusNode myFocusNode;
TextEditingController tempTextEditingController;
String labelText;
TextInputType keyboardType;
bool autofocus = false;
TextInputAction textInputAction;
List<TextInputFormatter> inputFormatters;
Function validation;
bool checkOfErrorOnFocusChange = false;//If true validation is checked when evre focus is changed
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _OutlineBorderTextFormField();
}
OutlineBorderTextFormField(
{#required this.labelText,
#required this.autofocus,
#required this.tempTextEditingController,
#required this.myFocusNode,
#required this.inputFormatters,
#required this.keyboardType,
#required this.textInputAction,
#required this.validation,
#required this.checkOfErrorOnFocusChange});
}
class _OutlineBorderTextFormField extends State<OutlineBorderTextFormField> {
bool isError = false;
String errorString = "";
getLabelTextStyle(color) {
return TextStyle(
fontSize: 12.0, color: color
);
} //label text style
getTextFieldStyle() {
return TextStyle(
fontSize: 12.0,
color: Colors.black,
);
} //textfield style
getErrorTextFieldStyle() {
return TextStyle(
fontSize: 10.0,
color: Colors.red,
);
}// Error text style
getBorderColor(isfous) {
return isfous
? Colors.deepPurple
: Colors.black54;
}//Border colors according to focus
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(left: 16.0, top: 15.0, right: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
FocusScope(
child: Focus(
onFocusChange: (focus) {
//Called when ever focus changes
print("focus: $focus");
setState(() {
getBorderColor(focus);
if (widget.checkOfErrorOnFocusChange &&
widget
.validation(widget.tempTextEditingController.text)
.toString()
.isNotEmpty) {
isError = true;
errorString = widget
.validation(widget.tempTextEditingController.text);
} else {
isError = false;
errorString = widget
.validation(widget.tempTextEditingController.text);
}
});
},
child: Container(
padding: EdgeInsets.all(2.0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(
6.0) // <--- border radius here
),
border: Border.all(
width: 1,
style: BorderStyle.solid,
color: isError
? Colors.red
: getBorderColor(widget.myFocusNode.hasFocus),
)),
child: TextFormField(
focusNode: widget.myFocusNode,
controller: widget.tempTextEditingController,
style: getTextFieldStyle(),
autofocus: widget.autofocus,
keyboardType: widget.keyboardType,
textInputAction: widget.textInputAction,
inputFormatters: widget.inputFormatters,
validator: (string) {
if (widget
.validation(widget.tempTextEditingController.text)
.toString()
.isNotEmpty) {
setState(() {
isError = true;
errorString = widget
.validation(widget.tempTextEditingController.text);
});
return "";
} else {
setState(() {
isError = false;
errorString = widget
.validation(widget.tempTextEditingController.text);
});
}
return null;
},
decoration: InputDecoration(
labelText: widget.labelText,
labelStyle: isError
? getLabelTextStyle(
Colors.red)
: getLabelTextStyle(Colors.deepPurple),
contentPadding:
EdgeInsets.symmetric(vertical: 7, horizontal: 16),
fillColor: Colors.grey[200],
filled: true,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
border: InputBorder.none,
errorStyle: TextStyle(height: 0),
focusedErrorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
hasFloatingPlaceholder: true),
),
),
),
),
Visibility(
visible: isError ? true : false,
child: Container(
padding: EdgeInsets.only(left: 15.0, top: 2.0),
child: Text(
errorString,
style: getErrorTextFieldStyle(),
))),
],
),
);
;
}
}
Example for calling this widget
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
FocusNode myFocusNode = new FocusNode();
TextEditingController tempTextEditingController = TextEditingController();
FocusNode myFocusNode1 = new FocusNode();
TextEditingController tempTextEditingController1 = TextEditingController();
void validateAndSave() {
final FormState form = _formKey.currentState;
if (form.validate()) {
print('Form is valid');
} else {
print('Form is invalid');
}
}
String getTempIFSCValidation(String text) {
return text.length > 5 ? "* Please enter valid IFSC Code" : "";
}
String getTempAccountValidation(String text) {
return text.length > 8 ? "* Please enter valid Account Number" : "";
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Form(
key: _formKey,
child: Column(
children: <Widget>[
OutlineBorderTextFormField(labelText: "Account Number*",myFocusNode: myFocusNode,tempTextEditingController: tempTextEditingController,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
autofocus: false,
checkOfErrorOnFocusChange: true,
inputFormatters: [
LengthLimitingTextInputFormatter(18),
WhitelistingTextInputFormatter.digitsOnly
],
validation: (textToValidate){
return getTempAccountValidation(textToValidate);
},),
OutlineBorderTextFormField(labelText: "Re- Enter Account Number*",myFocusNode: myFocusNode1,tempTextEditingController: tempTextEditingController1,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
autofocus: false,
checkOfErrorOnFocusChange: true,
inputFormatters: [
LengthLimitingTextInputFormatter(18),
WhitelistingTextInputFormatter.digitsOnly
],
validation: (textToValidate){
print("Value Validated");
return getTempIFSCValidation(textToValidate);
},),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: validateAndSave,//call the validation method
tooltip: 'Validate',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

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.