Hi im new to Flutter and coding and tried do build my first to do app. I've created a textformfield to add new todos with a button in a container above. I used the texteditingcontroller to get the userinput and stored the input in a variable. To test the outcome, I simply tried to display the information under the button, but it didnt work. When pressing the button, the text doesn't change. What did I do wrong here?
landing_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_application_1/presentation/widgets/to_do_section.dart';
class LandingPage extends StatefulWidget {
const LandingPage({Key? key}) : super(key: key);
#override
State<LandingPage> createState() => _LandingPageState();
}
class _LandingPageState extends State<LandingPage> {
#override
Widget build(BuildContext context) {
final _textController = TextEditingController();
String userInput = "";
return Scaffold(
appBar: AppBar(
title: const Center(child: Text("To-Do-App")),
backgroundColor: Colors.redAccent,
),
body: SingleChildScrollView(
child: Column(
children: [
const ToDos(),
Column(
children: [
Padding(
padding: EdgeInsets.only(top: 8.0, left: 20, right: 20, bottom: 20),
child: TextField(
controller: _textController,
textAlign: TextAlign.center,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: "Add a new ToDo",
) ,
),
),
MaterialButton(
color: Colors.redAccent,
onPressed: () {
setState(() {
userInput = _textController.text;
});
},
child: Text("Admit", style: TextStyle(color: Colors.white),),
),
Text(userInput)
],
)],
),
),
);
}
}
to_do_section.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_application_1/responsive_layout.dart';
class ToDos extends StatefulWidget {
const ToDos({Key? key, }) : super(key: key);
#override
State<ToDos> createState() => _ToDosState();
}
class _ToDosState extends State<ToDos> {
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Padding(
padding: EdgeInsets.only(
top: SizeConfig.blockSizeHorizontal * 10,
left: SizeConfig.blockSizeVertical * 2.5,
right: SizeConfig.blockSizeVertical * 2.5,
bottom: SizeConfig.screenHeight / 8
),
child: SizedBox(
width: SizeConfig.blockSizeHorizontal*100,
height: SizeConfig.blockSizeVertical*40,
child: Container(
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Colors.black45, style: BorderStyle.solid, width: 4)),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text("hi"),
]),
),
),
),
);
}
}
Move these 2 variable declaration outside the build method. The build method is called when you setState and then it rebuilds again. That's the reason its not updated.
final _textController = TextEditingController();
String userInput = "";
#override
Widget build(BuildContext context) {
}
Related
I want to achieve the animated search app bar: https://drive.google.com/file/d/1BnykuOZExHusxIRgareKmdaPM6RlswYe/view?usp=sharing
I tried to use a stack and an animated container, to achieve it. however, it was giving renderflex error.
I would like to know if anyone has other suggestions to achieve it.
Following is the code for the custom appbar and search widget:
AppBar:
class CustomHomeAppBar extends ConsumerStatefulWidget with PreferredSizeWidget {
#override
final Size preferredSize;
CustomHomeAppBar({Key? key, required this.title})
: preferredSize = const Size.fromHeight(60.0),
super(key: key);
final String title;
#override
ConsumerState<ConsumerStatefulWidget> createState() =>
_CustomHomeAppBarState();
}
class _CustomHomeAppBarState extends ConsumerState<CustomHomeAppBar> {
#override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
elevation: 0,
title: Stack(children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
InkWell(
onTap: () {},
child: const CircleAvatar(
radius: 18,
backgroundColor: Colors.teal,
child: CircleAvatar(
backgroundImage: NetworkImage(
"https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80"),
radius: 28,
),
),
),
const SizedBox(
width: 10,
),
Text(
widget.title,
style:
const TextStyle(fontWeight: FontWeight.w400, fontSize: 22),
),
],
),
Positioned(right: 0, child: AnimatedSearchBar())
]));
}
}
search widget:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
class AnimatedSearchBar extends StatefulWidget {
const AnimatedSearchBar({Key? key}) : super(key: key);
#override
State<AnimatedSearchBar> createState() => _AnimatedSearchBarState();
}
class _AnimatedSearchBarState extends State<AnimatedSearchBar> {
bool _folded = true;
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 400),
width: _folded ? 24 : MediaQuery.of(context).size.width - 16,
// height: 56,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
color: Colors.white,
),
child: Row(children: [
Expanded(
child: Container(
// padding: const EdgeInsets.only(left: 16),
decoration:
BoxDecoration(color: Color.fromARGB(255, 212, 207, 207)),
child: !_folded
? const TextField(
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(color: Colors.blue),
border: InputBorder.none))
: null,
),
),
AnimatedContainer(
duration: const Duration(milliseconds: 400),
child: InkWell(
onTap: () {
print("clicks");
setState(() {
_folded = !_folded;
});
},
// child: Padding(
// padding: const EdgeInsets.all(16.0),
child: Icon(
_folded ? Icons.search : Icons.close,
color: Colors.blue[900],
),
),
),
// )
]),
);
}
}
It results in the following appbar:
search with stack
Hi im new to Flutter and coding and tried do build my first to do app. I've created a textformfield to add new todos with a button in a container above. I used the texteditingcontroller to get the userinput and stored the input in a variable. I tried to display the userInput on a toDoSection, but it only appears, if im hot reloading the application. My button, which should do the work instead, doesn't work. What did I do wrong here?
landing_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_application_1/presentation/widgets/to_do_section.dart';
final _textController = TextEditingController();
String userInput = "";
class LandingPage extends StatefulWidget {
const LandingPage({Key? key}) : super(key: key);
#override
State<LandingPage> createState() => _LandingPageState();
}
class _LandingPageState extends State<LandingPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Center(child: Text("To-Do-App")),
backgroundColor: Colors.redAccent,
),
body: SingleChildScrollView(
child: Column(
children: [
const ToDos(),
ToDoAdd()
],
),
),
);
}
Column ToDoAdd() {
return Column(
children: [
Padding(
padding: EdgeInsets.only(top: 8.0, left: 20, right: 20, bottom: 20),
child: TextField(
controller: _textController,
textAlign: TextAlign.center,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: "Add a new ToDo",
) ,
),
),
MaterialButton(
color: Colors.redAccent,
onPressed: () {
setState(() {
userInput = _textController.text;
toDoList.add(userInput);
});
},
child: Text("Admit", style: TextStyle(color: Colors.white),),
),
Text(userInput)
],
);
}
}
to_do_section.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_application_1/presentation/widgets/landing_page.dart';
import 'package:flutter_application_1/responsive_layout.dart';
var toDoList = <String> [userInput];
class ToDos extends StatefulWidget {
const ToDos({Key? key, }) : super(key: key);
#override
State<ToDos> createState() => _ToDosState();
}
class _ToDosState extends State<ToDos> {
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Padding(
padding: EdgeInsets.only(
top: SizeConfig.blockSizeHorizontal * 10,
left: SizeConfig.blockSizeVertical * 2.5,
right: SizeConfig.blockSizeVertical * 2.5,
bottom: SizeConfig.screenHeight / 8
),
child: SizedBox(
width: SizeConfig.blockSizeHorizontal*100,
height: SizeConfig.blockSizeVertical*40,
child: Container(
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Colors.black45, style: BorderStyle.solid, width: 4)),
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Text(userInput)
]),
),
),
),
);
}
}
The following code should do the trick. The problem was not using setState to refresh the screen with the new data and not iterating over all values to display them (Also, moved global variables to local).
Check out the live demo on DartPad
And the 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: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const LandingPage(),
);
}
}
class LandingPage extends StatefulWidget {
const LandingPage({Key? key}) : super(key: key);
#override
State<LandingPage> createState() => _LandingPageState();
}
class _LandingPageState extends State<LandingPage> {
String userInput = "";
var toDoList = <String>[];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Center(child: Text("To-Do-App")),
backgroundColor: Colors.redAccent,
),
body: SingleChildScrollView(
child: Column(
children: [ToDos(list: toDoList), ToDoAdd()],
),
),
);
}
Column ToDoAdd() {
return Column(
children: [
Padding(
padding:
const EdgeInsets.only(top: 8.0, left: 20, right: 20, bottom: 20),
child: TextField(
onChanged: (value) => setState(() => userInput = value),
textAlign: TextAlign.center,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Add a new ToDo",
),
),
),
MaterialButton(
color: Colors.redAccent,
onPressed: () => setState(() => toDoList.add(userInput)),
child: const Text(
"Admit",
style: TextStyle(color: Colors.white),
),
),
Text(userInput)
],
);
}
}
class ToDos extends StatefulWidget {
final List<String> list;
const ToDos({
Key? key,
required this.list,
}) : super(key: key);
#override
State<ToDos> createState() => _ToDosState();
}
class _ToDosState extends State<ToDos> {
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Padding(
padding: EdgeInsets.only(
top: SizeConfig.blockSizeHorizontal * 10,
left: SizeConfig.blockSizeVertical * 2.5,
right: SizeConfig.blockSizeVertical * 2.5,
bottom: SizeConfig.screenHeight / 8),
child: SizedBox(
width: SizeConfig.blockSizeHorizontal * 100,
height: SizeConfig.blockSizeVertical * 40,
child: Container(
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Colors.black45, style: BorderStyle.solid, width: 4)),
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(children: [
for (final value in widget.list)
Text(value),
]),
),
),
),
);
}
}
class SizeConfig {
static late MediaQueryData _mediaQueryData;
static late double screenWidth;
static late double screenHeight;
static late double blockSizeHorizontal;
static late double blockSizeVertical;
static late double _safeAreaHorizontal;
static late double _safeAreaVertical;
static late double safeBlockHorizontal;
static late double safeBlockVertical;
void init(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
screenWidth = _mediaQueryData.size.width;
screenHeight = _mediaQueryData.size.height;
blockSizeHorizontal = screenWidth / 100;
blockSizeVertical = screenHeight / 100;
_safeAreaHorizontal =
_mediaQueryData.padding.left + _mediaQueryData.padding.right;
_safeAreaVertical =
_mediaQueryData.padding.top + _mediaQueryData.padding.bottom;
safeBlockHorizontal = (screenWidth - _safeAreaHorizontal) / 100;
safeBlockVertical = (screenHeight - _safeAreaVertical) / 100;
}
}
I'm not able to create a Listview in Flutter because of when I create a Listview of widgets the screen stays empty, it's something like that 1
This is the Code that I wrote and returns a list view:
import 'package:dietapp/pages/homepage.dart';
import 'package:dietapp/pages/list.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:dietapp/pages/profile.dart';
import 'package:dietapp/pages/createReg.dart';
import 'package:percent_indicator/percent_indicator.dart';
void main() {}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const SafeArea(child: TopBar()),
const Align(
alignment: Alignment.topLeft,
child: Padding(
padding: EdgeInsets.only(left: 25, bottom: 20),
child: Text('Seguiment Diari', style: TextStyle(fontSize: 20)),
)),
Align(alignment: Alignment.center, child: TypesListView()),
],
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const CreateReg()));
},
label: const Text('Crear'),
icon: const Icon(Icons.add),
),
);
}
}
class TopBar extends StatelessWidget {
const TopBar({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(25.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
"Dietapp",
style: TextStyle(
color: Colors.black, fontSize: 30, fontWeight: FontWeight.bold),
),
],
),
);
}
}
class TotalLabel extends StatefulWidget {
final String typeOf;
final String subtitle;
final Function() onPressed;
final double fillBar;
const TotalLabel(
{required this.typeOf,
required this.subtitle,
required this.onPressed,
required this.fillBar,
Key? key})
: super(key: key);
#override
State<TotalLabel> createState() => _TotalLabelState();
}
class _TotalLabelState extends State<TotalLabel> {
Color getColor(double fillBar) {
if (fillBar < 0.5) {
return Colors.orange;
} else {
return Colors.green;
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: widget.onPressed,
child: Container(
width: 350,
height: 125,
padding: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.5),
boxShadow: [
BoxShadow(
offset: const Offset(10, 20),
blurRadius: 10,
spreadRadius: 0,
color: Colors.grey.withOpacity(.05)),
],
),
child: Column(
children: [
Text(widget.typeOf,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20,
)),
const SizedBox(
height: 5,
),
Text(
widget.subtitle,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.grey,
fontWeight: FontWeight.normal,
fontSize: 12),
),
const SizedBox(
height: 10,
),
const Spacer(),
LinearPercentIndicator(
width: 300,
lineHeight: 10,
barRadius: const Radius.circular(50),
backgroundColor: Colors.black12,
progressColor: getColor(widget.fillBar),
percent: widget.fillBar,
),
const Spacer()
],
),
),
);
}
}
class TypesListView extends StatelessWidget {
const TypesListView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.all(8),
children: <Widget>[
TotalLabel(
typeOf: 'Proteines',
subtitle: 'Range',
onPressed: () {},
fillBar: 0.2),
],
);
}
}
When I run the code, the error view is the following:
I have also tried to use a Stateless widget returning a list view but didn't worked.
Thanks you so much :)
The following is an example of how to use a ListView. Note that I created a MaterialApp since ListView is a Material Widget. You can replace ListViewExample with your own Widget containing a ListView.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ListView Example',
home: ListViewExample(),
);
}
}
class ListViewExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.all(8),
children: <Widget>[
Text('Text Widget 1'),
Text('Text Widget 2'),
Text('Text Widget 3'),
],
);
}
}
ListView.builder(
itemCount: 5
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(10),
child: Text("Some text $index")
),
);
}),
More about listview
I have the DropDownButton widget below, The widget works well as intended. However, I want to reuse this widget within the app, and simply pass options to it.
As an example, I want to call the same widget, but pass a different Title to the "brand" title, which is in the Row, then change the values in the dropdown as well.
How can I do that?
Below is the 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 const MaterialApp(
title: 'FLUTTER DROPDOWN BUTTON',
home: MainPage(),
);
}
}
class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);
#override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
final brand = [
'ACER',
'APPLE',
'ASUS',
'DELL',
'HP',
'LENOVO',
'MICROSOFT',
'TOSHIBA',
];
String? value;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Dropdown Menu',
),
centerTitle: true,
),
body: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: const [
Padding(
padding: EdgeInsets.only(
left: 30.0,
bottom: 5.0,
),
child: Text(
"Brand",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
],
),
Container(
margin: const EdgeInsets.only(
left: 16.0,
right: 16.0,
),
padding: const EdgeInsets.symmetric(
horizontal: 12.0,
vertical: 4.0,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
16,
),
border: Border.all(
color: Colors.blue,
width: 3.0,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: value,
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.blue,
),
iconSize: 40.0,
isExpanded: true,
items: brand.map(buildMenuItem).toList(),
onChanged: (value) => setState(
() => this.value = value,
),
),
),
),
],
),
);
}
DropdownMenuItem<String> buildMenuItem(String item) => DropdownMenuItem(
value: item,
child: Text(
item,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
),
),
);
}
VsCode have support this method can help Extract an Widget to reuseable. Of course you if you want some more functional, you need to add your constructor property for your ow.
Follow below instruction.
Left your cursor on the Widget you want extract, click on the light bub
Select Extract Widget
Type the name for new Widget, then enter.
Create a class and return your dropdown Widget from it's build method.
import 'package:digital_show_room/utils/app_colors.dart';
import 'package:digital_show_room/utils/app_styles.dart';
import 'package:flutter/material.dart';
class AppDropDownButton<T> extends StatefulWidget {
final List<DropdownMenuItem<T>> dropdownMenuItemList;
final ValueChanged<T> onChanged;
final T value;
final bool isEnabled;
final bool isBorder;
final double radius;
final TextStyle? textStyle;
final Color? color;
final Widget? icon;
const AppDropDownButton({
Key? key,
required this.dropdownMenuItemList,
required this.onChanged,
required this.value,
this.isEnabled = true,
this.isBorder = false,
this.radius = 10.0,
this.textStyle,
this.color,
this.icon,
}) : super(key: key);
#override
_AppDropDownButtonState createState() => _AppDropDownButtonState();
}
class _AppDropDownButtonState extends State<AppDropDownButton> {
#override
Widget build(BuildContext context) {
return IgnorePointer(
ignoring: !widget.isEnabled,
child: Container(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(widget.radius)),
border: widget.isBorder
? Border.all(
color: AppColors.darkGrey,
width: 0,
)
: Border(),
color: widget.isEnabled
? (widget.color ?? AppColors.indigoLight)
: AppColors.lightGrey),
child: DropdownButtonHideUnderline(
child: DropdownButton(
isExpanded: true,
itemHeight: 50.0,
style: (widget.textStyle ?? AppStyles.subTitle16Style).copyWith(
color:
widget.isEnabled ? AppColors.darkBlue : AppColors.darkGrey),
items: widget.dropdownMenuItemList,
onChanged: widget.onChanged,
value: widget.value,
dropdownColor: AppColors.white,
iconEnabledColor: AppColors.grey,
icon: widget.icon ?? Icon(Icons.arrow_drop_down),
),
),
),
);
}
}
I am trying to create a login and register page for my app, I'm using the stateful widget on both screens.
after filling up the registration or login form and hiding the keyboard to press the register or login button, I'm getting the "string is empty" result, also on onPressed, I've tried to print my email and password in the console but I'm getting an empty field. But, if I try the same with my virtual keyboard still open on my virtual device, I'm able to print out the string, as far as I can understand the error is happening only when the keyboard is hidden.
this is my input field class
class RoundedInputField extends StatefulWidget {
final String hintText;
final ValueChanged<String> onChanged;
final Color color;
final bool boolean;
RoundedInputField({
Key key,
this.hintText,
this.onChanged,
this.color,
this.boolean = false,
}) : super(key: key);
#override
_RoundedInputFieldState createState() => _RoundedInputFieldState();
}
class _RoundedInputFieldState extends State<RoundedInputField> {
#override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
onChanged: widget.onChanged,
obscureText: widget.boolean,
decoration: InputDecoration(
hintText: widget.hintText,
border: InputBorder.none,
),
),
);
}
}
class TextFieldContainer extends StatefulWidget {
final Widget child;
final Color color;
const TextFieldContainer({
Key key,
this.child,
this.color: Colors.white,
}) : super(key: key);
#override
_TextFieldContainerState createState() => _TextFieldContainerState();
}
class _TextFieldContainerState extends State<TextFieldContainer> {
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 5),
width: size.width * 0.8,
decoration: BoxDecoration(
color: widget.color,
borderRadius: BorderRadius.circular(29),
),
child: widget.child,
);
}
}
and I call RoundedInputField
RoundedInputField(
hintText: "Email",
onChanged: (val) {
email = val;
},
this is my button for registering, currently im only printing the values
Container(
margin: EdgeInsets.symmetric(vertical: 10),
width: size.width * 0.8,
child: ClipRRect(
borderRadius: BorderRadius.circular(29),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 40),
color: Colors.white,
onPressed: () async {
print(email);
print(password);
},
child: Text(
'login',
style: GoogleFonts.montserrat(
color: HexColor(studentPrimaryColour), fontSize: 20),
),
),
),
),
this is my login screen
class StudentLoginScreen extends StatefulWidget {
StudentLoginScreen();
#override
_StudentLoginScreenState createState() => _StudentLoginScreenState();
}
class _StudentLoginScreenState extends State<StudentLoginScreen> {
#override
Widget build(BuildContext context) {
final AuthService _authService = AuthService();
Size size = MediaQuery.of(context).size;
String email = '';
String password = '';
return Scaffold(
backgroundColor: HexColor(studentPrimaryColour),
body: SafeArea(
child: ListView(
children: <Widget>[
SizedBox(
height: 25.0,
),
HeadingText(
text: 'Login',
size: 60.0,
color: Colors.white,
),
SizedBox(
height: 25.0,
),
RoundedInputField(
hintText: "Email",
onChanged: (val) {
email = val;
},
),
SizedBox(
height: 5.0,
),
RoundedInputField(
hintText: "Password",
boolean: true,
onChanged: (val) {
password = val;
},
),
SizedBox(
height: 15.0,
),
Container(
margin: EdgeInsets.symmetric(vertical: 10),
width: size.width * 0.8,
child: ClipRRect(
borderRadius: BorderRadius.circular(29),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 40),
color: Colors.white,
onPressed: () async {
print(email);
print(password);
},
child: Text(
'login',
style: GoogleFonts.montserrat(
color: HexColor(studentPrimaryColour), fontSize: 20),
),
),
),
),
SizedBox(
height: 15.0,
),
InkWell(
onTap: () {
Navigator.pushNamed(context, '/studentRegisterScreen');
},
child: HeadingText(
text: 'register?',
color: Colors.white,
size: 10,
),
),
],
),
),
);
}
}
Inside your login screen, you declared and initialised both properties email and password inside the build method. What this essentially means is, that as soon as your login widget gets rebuilded (for example when hiding the keyboard since Flutter has to recalculate size and so on) both properties are initialised again with ''.
Thats what StatefulWidget are also for - defining properties as part of the state, without being part of the build cycle. In other words, change it up to this:
class StudentLoginScreen extends StatefulWidget {
StudentLoginScreen();
#override
_StudentLoginScreenState createState() => _StudentLoginScreenState();
}
class _StudentLoginScreenState extends State<StudentLoginScreen> {
String email = '';
String password = '';
#override
Widget build(BuildContext context) {
...
}