Flutter / Dart - I have a simple app but am new to programming, so struggling.
Currently, the setup is with all the TextInput boxes in a Column. I would like to change this to having them in a Row. I assumed this would be easy by simply replacing the Word Column with Row on line 44. But it doesn't work and when I try to run it, the "errors_patch.dart" page opens (which I have never seen before) with a highlighted error on line 51 "int assertionStart, int assertionEnd, Object? message);".
How can I simply change from Column to Row?
How can I have the result show in real time rather than needing to click on the "Subtraction" button to get it?
Many thanks in advance.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
const appTitle = 'Help with a meal....';
return MaterialApp(
debugShowCheckedModeBanner: false,
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
backgroundColor: Colors.grey,
foregroundColor: Colors.black,
),
body: const AddTwoNumbers(),
),
);
}
}
class AddTwoNumbers extends StatefulWidget {
const AddTwoNumbers({super.key});
#override
// ignore: library_private_types_in_public_api
_AddTwoNumbersState createState() => _AddTwoNumbersState();
}
class _AddTwoNumbersState extends State<AddTwoNumbers> {
TextEditingController num1controller = TextEditingController();
TextEditingController num2controller = TextEditingController();
TextEditingController num3controller = TextEditingController();
TextEditingController num4controller = TextEditingController();
String result = "0";
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
TextField(
keyboardType: const TextInputType.numberWithOptions(decimal: true),
controller: num1controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Target Level',
hintText: 'Enter First Number',
),
),
const SizedBox(
height: 8,
),
TextField(
keyboardType: const TextInputType.numberWithOptions(decimal: true),
controller: num2controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Level',
hintText: 'Enter Second Number',
),
),
const SizedBox(
height: 8,
),
TextField(
keyboardType: const TextInputType.numberWithOptions(decimal: true),
controller: num3controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs',
hintText: 'Enter Third Number',
),
),
const SizedBox(
height: 8,
),
TextField(
keyboardType: const TextInputType.numberWithOptions(decimal: true),
controller: num4controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs 2',
hintText: 'Enter Fourth Number',
),
),
const SizedBox(
height: 8,
),
Wrap(children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.purple),
child: const Text("Subtraction"),
onPressed: () {
setState(() {
double sum = double.parse(num1controller.text) -
double.parse(num2controller.text);
result = sum.toStringAsFixed(1);
});
},
),
const SizedBox(
height: 20,
width: 20,
),
]),
Text('Difference between Target Level and Current Level: $result'),
],
),
);
}
}
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
const appTitle = 'Help with a meal....';
return MaterialApp(
debugShowCheckedModeBanner: false,
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
backgroundColor: Colors.grey,
foregroundColor: Colors.black,
),
body: const AddTwoNumbers(),
),
);
}
}
class AddTwoNumbers extends StatefulWidget {
const AddTwoNumbers({super.key});
#override
// ignore: library_private_types_in_public_api
_AddTwoNumbersState createState() => _AddTwoNumbersState();
}
class _AddTwoNumbersState extends State<AddTwoNumbers> {
TextEditingController num1controller = TextEditingController();
TextEditingController num2controller = TextEditingController();
TextEditingController num3controller = TextEditingController();
TextEditingController num4controller = TextEditingController();
String result = "0";
_calculate() {
if (num1controller.text.isNotEmpty && num2controller.text.isNotEmpty) {
setState(() {
double sum = double.parse(num1controller.text) -
double.parse(num2controller.text);
result = sum.toStringAsFixed(1);
});
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Row(
children: <Widget>[
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num1controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Target Level',
hintText: 'Enter First Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num2controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Level',
hintText: 'Enter Second Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num3controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs',
hintText: 'Enter Third Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num4controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs 2',
hintText: 'Enter Fourth Number',
),
),
),
const SizedBox(
width: 8,
),
],
),
Text(
'Difference between Target Level and Current Level: $result'),
],
),
),
),
);
}
}
Since you are switching to Row it doesn't know the width of the TextFields, so you need to wrap them with Expanded or Flexible widgets to make them take the space they need (or you can give them some fixed width if you wish), something like in the solution below. And the answer to the second question is also in the solution, you just call the calculate method on every TextField change.
class AddTwoNumbers extends StatefulWidget {
const AddTwoNumbers({Key? key}) : super(key: key);
#override
// ignore: library_private_types_in_public_api
_AddTwoNumbersState createState() => _AddTwoNumbersState();
}
class _AddTwoNumbersState extends State<AddTwoNumbers> {
TextEditingController num1controller = TextEditingController();
TextEditingController num2controller = TextEditingController();
TextEditingController num3controller = TextEditingController();
TextEditingController num4controller = TextEditingController();
String result = "0";
_calculate() {
setState(() {
double sum =
double.parse(num1controller.text) - double.parse(num2controller.text);
result = sum.toStringAsFixed(1);
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Row(
children: <Widget>[
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num1controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Target Level',
hintText: 'Enter First Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num2controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Level',
hintText: 'Enter Second Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num3controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs',
hintText: 'Enter Third Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num4controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs 2',
hintText: 'Enter Fourth Number',
),
),
),
const SizedBox(
width: 8,
),
],
),
Text(
'Difference between Target Level and Current Level: $result'),
],
),
),
),
);
}
}
There are many ways to do what you're trying to achieve. For changing Column to Rows, you can use a container with a column as a child and rows as children in it. You can see the documentation for further assistance.
For your second question, you can use onChanged() callback or you can use TextEditingController to see the realtime changes in your TextField.
Related
Flutter / Dart - I have a simple diabetic app but am new to programming, so struggling a lot, even after watching hours of Flutter youtube videos! My app currently has 4 input fields on one row and the result of a calculation of input1 - input2 below it. I would like to change this, so that the top row has Input / Input / Output (in similar boxes) and the second row has Input / Input / Output (in similar boxes). The code for my current app is shown below after some help on Stackoverflow. It has been suggested that I use the command "resultTextFieldController.text = resultOfCalculation;" to put the result in a text box, but my main issue is where to put that line as everywhere I have put it so far, the line gets underlined in red.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
const appTitle = 'Help with a meal....';
return MaterialApp(
debugShowCheckedModeBanner: false,
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
backgroundColor: Colors.grey,
foregroundColor: Colors.black,
),
body: const AddTwoNumbers(),
),
);
}
}
class AddTwoNumbers extends StatefulWidget {
const AddTwoNumbers({super.key});
#override
// ignore: library_private_types_in_public_api
_AddTwoNumbersState createState() => _AddTwoNumbersState();
}
class _AddTwoNumbersState extends State<AddTwoNumbers> {
TextEditingController num1controller = TextEditingController();
TextEditingController num2controller = TextEditingController();
TextEditingController num3controller = TextEditingController();
TextEditingController num4controller = TextEditingController();
String result = "0";
_calculate() {
if (num1controller.text.isNotEmpty && num2controller.text.isNotEmpty) {
setState(() {
double sum = double.parse(num1controller.text) -
double.parse(num2controller.text);
result = sum.toStringAsFixed(1);
});
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Row(
children: <Widget>[
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num1controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Target Level',
hintText: 'Enter First Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num2controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Level',
hintText: 'Enter Second Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num3controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs',
hintText: 'Enter Third Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
onChanged: (value) => _calculate(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: num4controller,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs 2',
hintText: 'Enter Fourth Number',
),
),
),
const SizedBox(
width: 8,
),
],
),
Text(
'Difference between Target Level and Current Level: $result'),
],
),
),
),
);
}
}
Full Code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
const appTitle = 'Help with a meal....';
return MaterialApp(
debugShowCheckedModeBanner: false,
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
backgroundColor: Colors.grey,
foregroundColor: Colors.black,
),
body: const AddTwoNumbers(),
),
);
}
}
class AddTwoNumbers extends StatefulWidget {
const AddTwoNumbers({super.key});
#override
// ignore: library_private_types_in_public_api
_AddTwoNumbersState createState() => _AddTwoNumbersState();
}
class _AddTwoNumbersState extends State<AddTwoNumbers> {
TextEditingController numR1C1controller =
TextEditingController(); //Changed name of the texteditingcontroller as Row as R and Column as C
TextEditingController numR1C2controller = TextEditingController();
TextEditingController numR1C3controller = TextEditingController();
TextEditingController numR2C1controller = TextEditingController();
TextEditingController numR2C2controller = TextEditingController();
TextEditingController numR2C3controller = TextEditingController();
String result = "0";
String result2 = "0";
_calculateR1() {
if (numR1C1controller.text.isNotEmpty &&
numR1C2controller.text.isNotEmpty) {
setState(() {
double sum = double.parse(numR1C1controller.text) -
double.parse(numR1C2controller.text);
numR1C3controller.text = sum.toStringAsFixed(1);
result = sum.toStringAsFixed(1);
});
}
}
_calculateR2() {
if (numR2C1controller.text.isNotEmpty &&
numR2C2controller.text.isNotEmpty) {
setState(() {
double sum = double.parse(numR2C1controller.text) -
double.parse(numR2C2controller.text);
numR2C3controller.text = sum.toStringAsFixed(1);
result2 = sum.toStringAsFixed(1);
});
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Row(
children: <Widget>[
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR1(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR1C1controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Target Level',
hintText: 'Enter First Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR1(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR1C2controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Level',
hintText: 'Enter Second Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR1(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR1C3controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Result',
hintText: '',
),
),
),
const SizedBox(
width: 8,
),
],
),
const SizedBox(
height: 8,
),
Row(
children: [
Expanded(
child: TextField(
onChanged: (value) => _calculateR2(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR2C1controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs',
hintText: 'Enter Third Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
onChanged: (value) => _calculateR2(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR2C2controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Meal carbs 2',
hintText: 'Enter Fourth Number',
),
),
),
const SizedBox(
width: 8,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
onChanged: (value) => _calculateR2(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: numR2C3controller,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Result',
hintText: '',
),
),
),
const SizedBox(
width: 8,
),
],
),
Text(
'Difference between Target Level and Current Level: $result'),
],
),
),
),
);
}
}
Output
Add this line to the textfield widget to allow only numbers to be inputted in the text field.
inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
Hope this helps. Happy Coding :)
I'm new in flutter, Can someone help me how to access the ss variable or the setState protected method of a State class I created inside of a Widget outside that class. I'm trying to organize codes that's why I extract the Widget out of that State class.
main.dart
import 'package:flutter/material.dart';
import 'screens.dart';
void main() => runApp(const App());
enum ScreenState {
home,
login,
register,
}
class App extends StatefulWidget {
const App({super.key});
#override
State<StatefulWidget> createState() => _AppState();
}
class _AppState extends State<App> {
ScreenState ss = ScreenState.register;
#override
Widget build(BuildContext context) {
switch (ss) {
case ScreenState.register:
return registerPage();
default:
return registerPage();
}
}
}
screens.dart
import 'package:flutter/material.dart';
import 'components.dart';
Widget registerPage() {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.blueGrey,
),
home: Scaffold(
appBar: appHeader(),
body: registerForm(),
),
);
}
components.dart
import 'package:flutter/material.dart';
PreferredSizeWidget appHeader() {
return AppBar(
title: const Text('Register Form'),
actions: [
TextButton(
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Text(
'Home',
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline,
),
),
),
onPressed: () {/* _AppState.ss = ScreenState.home; */},
),
TextButton(
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Text(
'Log In',
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline,
),
),
),
onPressed: () {/* _AppState.ss = ScreenState.login; */},
),
],
);
}
Widget registerForm() {
return SingleChildScrollView(
child: Center(
child: Container(
constraints: const BoxConstraints(
minWidth: 300,
maxWidth: 500,
),
padding: const EdgeInsets.symmetric(
vertical: 40,
horizontal: 20,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text('Account Information'),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'Create username',
hintText: 'Enter username',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please create a username' : null;
},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
labelText: 'Create password',
hintText: 'Enter password',
prefixIcon: Icon(Icons.lock),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please create a password' : null;
},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
labelText: 'Re-enter password',
hintText: 'Enter password',
prefixIcon: Icon(Icons.lock),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please re-enter password' : null;
},
),
const SizedBox(
height: 30,
),
const Text('Personal information'),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'Last name',
hintText: 'Enter your last name',
prefixIcon: Icon(Icons.edit),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please enter your last name' : null;
},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'First name',
hintText: 'Enter your first name',
prefixIcon: Icon(Icons.edit),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please enter your first name' : null;
},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'Middle name (optional)',
hintText: 'Enter your middle name',
prefixIcon: Icon(Icons.edit),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'Suffix (optional)',
hintText: 'Enter your suffix',
prefixIcon: Icon(Icons.edit),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
),
],
),
),
),
);
}
I commented out the code that I expect to work but it turns out to be an error. Please teach me on how to fix the error. Thank you so much.
You can change your state to this:
class _AppState extends State<App> {
ScreenState ss = ScreenState.register;
#override
Widget build(BuildContext context) {
switch (ss) {
case ScreenState.register:
return registerPage(changeState);
default:
return registerPage(changeState);
}
}
void changeState(ScreenState s) {
setState(() {
ss = s;
});
}
}
Then registerPage like
Widget registerPage(Function(ScreenState) f) {
with
appBar: appHeader(f),
and then appHeader like
PreferredSizeWidget appHeader(Function(ScreenState) f) {
and then this for example:
onPressed: () {f(ScreenState.home);},
how can I call a function whenever there is a change in TextFormField .
I have many of them and it's more like an invoice.
So whenever the user changes a value, I need to make some mathematical operations.
The problem is that sometimes some TextFormField could be NULL (User did'tn insert a value yet) and that causes an error.
import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
late TextEditingController age = TextEditingController();
late TextEditingController height = TextEditingController();
late TextEditingController weight = TextEditingController();
late TextEditingController result = TextEditingController();
return Scaffold(
appBar: AppBar(
title: const Text('BMI !'),
),
body: Center(
child: DecoratedBox(
decoration: const BoxDecoration(
color: Colors.white10,
),
child: Padding(
padding: const EdgeInsets.all(48.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller:age,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: 'AGE',
),
),
TextFormField(
controller:height,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: 'HEIGHT',
),
),
TextFormField(
controller:weight,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: 'WEIGHT',
),
),
TextFormField(
enabled:false,
controller:result,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: 'Result',
),
),
],
),
),
),
),
);
}
}
void main() {
runApp(
MaterialApp(
home: MyApp(),
),
);
}
To call a function every time the TextFormField has a change, there's a property for exactly that!
the onChanged property, which fires every time something is typed:
return TextFormField(
onChanged: (value) {
// do something with `value`
},);
Since this is only called once there's a change, you don't have to worry about null
Edit: you can check if the controler.isNotEmpty and do something based on that:
void onChanged(String value){
if (_controller.text.isNotEmpty && _secondController.text.isNotEmpty) {
// do something
} else {
// do something
}
}
return TextFormField(
controller: _controller,
onChanged: (value) => onChanged(value),);
I want to set background image in to my code but I got this error "Another exception was thrown: Unable to load asset: assets/Onepiece-1.jpg" this one is the error actually it is not an error but the image doesn't appear in the background. I already set my image to in pubspec.yml.I just don't know how to set properly in my code and i dont know what the problem is can some one help my how to fix this error.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Registration Form',
theme: ThemeData(
primarySwatch: Colors.teal,
),
home: const MyHomePage(title: 'Registration'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController nameController = TextEditingController();
TextEditingController nameController2 = TextEditingController();
TextEditingController nameController3 = TextEditingController();
bool showPassword = false;
TextEditingController nameController4 = TextEditingController();
TextEditingController nameController5 = TextEditingController();
TextEditingController nameController6 = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {},
label: Text('Register'),
icon: const Icon(Icons.upload_file_sharp),
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/Onepiece-1.jpg"),
fit: BoxFit.cover,
),
),
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Username',
),
onChanged: (Text) {
setState(() {});
},
)),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController2,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Email Address',
),
onChanged: (Text) {
setState(() {});
},
)),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController3,
obscureText: showPassword,
obscuringCharacter: "*",
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
),
onChanged: (Text) {
setState(() {});
},
)),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController4,
obscureText: showPassword,
obscuringCharacter: "*",
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Confirm Password',
),
onChanged: (Text) {
setState(() {});
},
)),
TextButton(
onPressed: () {
setState(() {
showPassword = !showPassword;
});
},
child: Text('Show / Hide Password')
),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController5,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Address',
),
onChanged: (Text) {
setState(() {});
},
)),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController6,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Phone Number',
),
onChanged: (Text) {
setState(() {});
},
)),
])));
}
}
assets Directory
pubspec.yaml
assets:
- assets/images/
source code
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Registration Form',
theme: ThemeData(
primarySwatch: Colors.teal,
),
home: const MyHomePage(title: 'Registration'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController nameController = TextEditingController();
TextEditingController nameController2 = TextEditingController();
TextEditingController nameController3 = TextEditingController();
bool showPassword = false;
TextEditingController nameController4 = TextEditingController();
TextEditingController nameController5 = TextEditingController();
TextEditingController nameController6 = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {},
label: Text('Register'),
icon: const Icon(Icons.upload_file_sharp),
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/1-1.JPG"),
fit: BoxFit.cover,
),
),
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Username',
),
onChanged: (Text) {
setState(() {});
},
)),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController2,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Email Address',
),
onChanged: (Text) {
setState(() {});
},
)),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController3,
obscureText: showPassword,
obscuringCharacter: "*",
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
),
onChanged: (Text) {
setState(() {});
},
)),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController4,
obscureText: showPassword,
obscuringCharacter: "*",
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Confirm Password',
),
onChanged: (Text) {
setState(() {});
},
)),
TextButton(
onPressed: () {
setState(() {
showPassword = !showPassword;
});
},
child: Text('Show / Hide Password')
),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController5,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Address',
),
onChanged: (Text) {
setState(() {});
},
)),
Container(
margin: EdgeInsets.all(15),
child: TextField(
controller: nameController6,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Phone Number',
),
onChanged: (Text) {
setState(() {});
},
)),
])));
}
}
I am fairly new to flutter and dart as a whole and i have been creating an application that interacts with firebase, this is the code for my registration screen. When clicking on a text input field the keyboard ends up blocking the forms and you cannot see what you are entering... I have tried many things such as singlechildscroll view and resizeToAvoidBottomInset and nothing seems to be affecting it. Anyone have any idea?
Register page:
class RegistrationPage extends StatefulWidget{
const RegistrationPage({Key? key}) : super(key: key);
#override
_RegistrationPageState createState() => _RegistrationPageState();
}
class _RegistrationPageState extends State<RegistrationPage> {
final _auth = FirebaseAuth.instance;
//our form key
final _formKey = GlobalKey<FormState>();
//editing controllers
final firstNameEditingController = new TextEditingController();
final lastNameEditingController = new TextEditingController();
final emailEditingController = new TextEditingController();
final passwordEditingController = new TextEditingController();
final confirmPasswordEditingController = new TextEditingController();
final cityEditingController = new TextEditingController();
#override
Widget build(BuildContext context) {
//firstname Field
final firstNameField = TextFormField(
autofocus: false,
controller: firstNameEditingController,
keyboardType: TextInputType.name,
validator: (value)
{
RegExp regEx = new RegExp(r'^.{2,}$');
if(value!.isEmpty)
{
return("First Name cannot be empty");
}
if(!regEx.hasMatch(value))
{
return("Enter valid name(min 2 characters)");
}
return null;
},
onSaved: (value) {
firstNameEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.face),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "First name",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
));
//Last name Field
final lastNameField = TextFormField(
autofocus: false,
controller: lastNameEditingController,
keyboardType: TextInputType.name,
validator: (value)
{
RegExp regEx = new RegExp(r'^.{2,}$');
if(value!.isEmpty)
{
return("Last Name cannot be empty");
}
return null;
},
onSaved: (value) {
lastNameEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.face),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Last name",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
));
//email Field
final emailField = TextFormField(
autofocus: false,
controller: emailEditingController,
keyboardType: TextInputType.text,
validator: (value)
{
if(value!.isEmpty)
{
return("Please enter your email");
}
//email validation
if(!RegExp("^[a-zA-Z0-9+_.-]+#[a-zA-Z0-9.-]+.[a-z]").hasMatch(value))
{
return("Please enter a valid email");
}
},
onSaved: (value) {
emailEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.account_circle),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Email address",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
));
//City
final cityField = TextFormField(
autofocus: false,
controller: cityEditingController,
keyboardType: TextInputType.text,
validator: (value)
{
RegExp regEx = new RegExp(r'^.{2,}$');
if(value!.isEmpty)
{
return("City cannot be empty");
}
return null;
},
onSaved: (value) {
cityEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.location_on),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "City",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
));
//password Field
final passwordField = TextFormField(
autofocus: false,
controller: passwordEditingController,
obscureText: true,
validator: (value)
{
RegExp regEx = new RegExp(r'^.{6,}$');
if(value!.isEmpty)
{
return("Password is required!");
}
if(!regEx.hasMatch(value))
{
return("Enter valid password(Min. 6 characters)");
}
},
onSaved: (value) {
passwordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
)
);
//Confirm password Field
final confirmPasswordField = TextFormField(
autofocus: false,
controller: confirmPasswordEditingController,
obscureText: true,
validator: (value)
{
if (confirmPasswordEditingController.text != passwordEditingController.text){
return "Passwords do not match";
}
return null;
},
onSaved: (value) {
confirmPasswordEditingController.text = value!;
},
textInputAction: TextInputAction.done,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Confirm Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
)
);
final registerButton = Material(
elevation: 5,
borderRadius: BorderRadius.circular(30),
color: Colors.pink,
child: MaterialButton(
padding: EdgeInsets.fromLTRB(20, 15, 20, 15),
minWidth: MediaQuery.of(context).size.width,
onPressed: () {
signUp(emailEditingController.text, passwordEditingController.text);
},
child: Text("Register", textAlign:TextAlign.center,
style: TextStyle(
fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold),
),
)
);
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.pink),
onPressed:(){
Navigator.of(context).pop();
},
)
),
body: Center(
child: new SingleChildScrollView(
reverse: true,
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(36.0),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 180,
child: Image.asset(
"assets/logo.png",
fit: BoxFit.contain,
)),
SizedBox(height: 30),
firstNameField,
SizedBox(height: 10),
lastNameField,
SizedBox(height: 10),
emailField,
SizedBox(height:10),
cityField,
SizedBox(height: 10),
passwordField,
SizedBox(height: 10),
confirmPasswordField,
SizedBox(height: 10),
registerButton,
],
),
),
)
)
)
)
);
Main.dart
Future<void> main() async { //asynchronous programming, waits for events to happen before producing a result
WidgetsFlutterBinding.ensureInitialized(); //in this case initializes the Firebase waits for a callback
await Firebase.initializeApp();
runApp(const MyApp());
}
class MyApp extends StatelessWidget { //Used to build application
const MyApp({Key? key}) : super(key: key); //Anything in here runs when the app starts
ThemeData _appTheme() { //The login screen is first to load but this is not in place of main as it is bad practise
final ThemeData base = ThemeData.light(); //Will be used for implementation of light and dark theme
return base.copyWith(
colorScheme: base.colorScheme.copyWith(
primary: travelBlue,
onPrimary: Colors.white,
secondary: travelBlue,
error: travelErrorRed,
),
);
}
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp( //Runs when main.dart is executed
title: 'Login',
theme: _appTheme(),
home: LoginPage(),
);
}
}
try wrapping your column with padding
Padding(
padding: MediaQuery.of(context).viewInsets,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
// your entire form widgets here
]
)
)