Flutter- SingleChildScrollview dont scroll on keybord popup [duplicate] - flutter

This question already has answers here:
Flutter TextFormField hidden by keyboard
(13 answers)
Closed 2 years ago.
I'm trying to integrate a signup page. On the keyboard popup, it covers the some input fields on the bottom. Already implemented the Singlechildscrollview. It wont adjust while the keyboard popup. Tried using resizeToAvoidBottomPadding and some other solution, bu no luck. Please help thanks in advance for your help
class _EnterUserDetailsWidgetState extends State<EnterUserDetailsWidget> {
#override
Widget build(BuildContext context) {
final String assetName = 'assets/images/app_logo.svg';
final String pageBg = 'assets/images/user_auth_bg.png';
final String app_logo = 'assets/images/fram_collection_logo.png';
final String phoneIcon = 'assets/images/farm.png';
final _nameController = TextEditingController();
final _phoneController = TextEditingController();
final _emailController = TextEditingController();
final _formKey = GlobalKey<FormState>();
final FocusNode _nameFocusNode = FocusNode();
final FocusNode _emailFocusNode = FocusNode();
final FocusNode _phoneNumberNode = FocusNode();
final FocusNode _dummy = FocusNode();
final itemSpacing = 15.0;
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Stack(
children: [
Image(
image: AssetImage(pageBg),
fit: BoxFit.fill,
height: double.infinity,
width: double.infinity,
),
Container(
height: double.maxFinite,
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 50, bottom: 50),
child: Image(
height: 170,
filterQuality: FilterQuality.high,
image: AssetImage(app_logo),
fit: BoxFit.fitWidth,
),
),
TextFormField(
autofocus: true,
decoration: inputDecorationFeild(
hintText: "Email",
labelText: "Enter Email",
textFeildIcon: FarmCollection.email)),
TextFormField(
autofocus: true,
decoration: inputDecorationFeild(
hintText: "Email",
labelText: "Enter Email",
textFeildIcon: FarmCollection.email)),
TextFormField(
autofocus: true,
decoration: inputDecorationFeild(
hintText: "Email",
labelText: "Enter Email",
textFeildIcon: FarmCollection.email)),
TextFormField(
autofocus: true,
decoration: inputDecorationFeild(
hintText: "Email",
labelText: "Enter Email",
textFeildIcon: FarmCollection.email)),
TextFormField(
autofocus: true,
decoration: inputDecorationFeild(
hintText: "Email",
labelText: "Enter Email",
textFeildIcon: FarmCollection.email)),
curvedButtonGreen(
buttonText: "Submit",
onClick: () async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => OTPverificationWidget(),
),
);
},
),
],
),
),
),
],
),
);
}
_fieldFocusChange(BuildContext context, FocusNode nextFocus) {
// currentFocus.unfocus();
FocusScope.of(context).requestFocus(nextFocus);
}
}

I fixed and share you full code.
Because I don't have a asset file and some component, I replaced with Container or changed.
The main change point is 'resizeToAvoidBottomPadding: true' or remove that.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
final String assetName = 'assets/images/app_logo.svg';
final String pageBg = 'assets/images/user_auth_bg.png';
final String app_logo = 'assets/images/fram_collection_logo.png';
final String phoneIcon = 'assets/images/farm.png';
final _nameController = TextEditingController();
final _phoneController = TextEditingController();
final _emailController = TextEditingController();
final _formKey = GlobalKey<FormState>();
final FocusNode _nameFocusNode = FocusNode();
final FocusNode _emailFocusNode = FocusNode();
final FocusNode _phoneNumberNode = FocusNode();
final FocusNode _dummy = FocusNode();
final itemSpacing = 15.0;
return Scaffold(
resizeToAvoidBottomPadding: true,
body: Stack(
children: [
Container(height: 200),
Container(
height: double.maxFinite,
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 50, bottom: 50),
child: Container(height: 170),
// child: Image(
// height: 170,
// filterQuality: FilterQuality.high,
// image: AssetImage(app_logo),
// fit: BoxFit.fitWidth,
// ),
),
TextFormField(
autofocus: true,
decoration: InputDecoration(
hintText: "Email",
labelText: "Enter Email",
),
),
TextFormField(
autofocus: true,
decoration: InputDecoration(
hintText: "Email",
labelText: "Enter Email",
),
),
TextFormField(
autofocus: true,
decoration: InputDecoration(
hintText: "Email",
labelText: "Enter Email",
),
),
TextFormField(
autofocus: true,
decoration: InputDecoration(
hintText: "Email",
labelText: "Enter Email",
),
),
TextFormField(
autofocus: true,
decoration: InputDecoration(
hintText: "Email",
labelText: "Enter Email",
),
),
// curvedButtonGreen(
// buttonText: "Submit",
// onClick: () async {
// // await Navigator.of(context).push(
// // MaterialPageRoute(
// // builder: (context) => OTPverificationWidget(),
// // ),
// // );
// },
// ),
],
),
),
),
],
),
);
}
_fieldFocusChange(BuildContext context, FocusNode nextFocus) {
// currentFocus.unfocus();
FocusScope.of(context).requestFocus(nextFocus);
}
}

Related

Validate Elevated Button in Flutter

I'm making an app using Flutter which calculates motor vehicle tax.
It calculates it perfectly fine when I enter the cost of vehicle.
But I want to add a validation to it. When I don't enter any cost of vehicle and keeps it empty and then click the calculate button, I want it show - please enter the cost.
How do I add this validation as this is not a form.
Here is the code of that part:
TextField(
controller: costController,
decoration: const InputDecoration(labelText: "Cost of Vehicle"),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
),
const SizedBox(
height: 20,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
onPressed: () {
setState(() {
toPrint = calc(
dropDownValue!,
int.parse(costController.text),
).toString();
});
},
child: const Text("Calculate")),
const SizedBox(
height: 20,
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: Colors.lightGreenAccent[100],
border: const Border(
bottom: BorderSide(color: Colors.grey),
)),
child: Text("Tax : $toPrint "),
),
Wrap the column with a Form widget add avalidator to the textfield
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 = 'Form Validation Demo';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
),
body: const MyCustomForm(),
),
);
}
}
// Create a Form widget.
class MyCustomForm extends StatefulWidget {
const MyCustomForm({super.key});
#override
MyCustomFormState createState() {
return MyCustomFormState();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
//
// Note: This is a GlobalKey<FormState>,
// not a GlobalKey<MyCustomFormState>.
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: costController,
decoration: const InputDecoration(labelText: "Cost of Vehicle"),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
// The validator receives the text that the user has entered.
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
onPressed: () {
if (_formKey.currentState!.validate()) {
setState(() {
toPrint = calc(
dropDownValue!, int.parse(costController.text),
).toString();
});
}
},
child: const Text("Calculate")),
const SizedBox(
height: 20,
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: Colors.lightGreenAccent[100],
border: const Border(
bottom: BorderSide(color: Colors.grey),
)),
child: Text("Tax : $toPrint "),
),
],
),
);
}
}
Use Form Widget and Convert TextField to TextFormField like that.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class FormWidget extends StatefulWidget {
const FormWidget({Key? key}) : super(key: key);
#override
State<FormWidget> createState() => _FormWidgetState();
}
class _FormWidgetState extends State<FormWidget> {
final TextEditingController costController = TextEditingController();
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _formKey,
body: Column(
children: [
Form(
child: TextFormField(
validator: (value) {
if (value.isEmpty) {
return "Please enter the cost.";
}
return null;
},
controller: costController,
decoration: const InputDecoration(labelText: "Cost of Vehicle"),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
),
),
const SizedBox(
height: 20,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
onPressed: () {
if(_formKey.currentState.validate()){
//do your setState stuff
setState(() {
});
}
},
child: const Text("Calculate")),
const SizedBox(
height: 20,
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: Colors.lightGreenAccent[100],
border: const Border(
bottom: BorderSide(color: Colors.grey),
)),
child: Text("Tax : "),
),
],
),
);
}
}

How to scroll dialog content to focused TextField in Flutter?

I have a dialog with long content and many TextFields - at the top, middle and bottom. This is my test code
import 'package:flutter/material.dart';
class TempDialog extends StatefulWidget {
TempDialog({Key? key}) : super(key: key);
#override
State<TempDialog> createState() => _TempDialogState();
}
class _TempDialogState extends State<TempDialog> {
#override
Widget build(BuildContext context) {
var textController = TextEditingController(text: "");
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return AlertDialog(
content: Container(
width: width,
height: height,
child: Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.green,
filled: true
),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
controller: textController,
),
SizedBox(height: 500,),
TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.red,
filled: true
),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
controller: textController,
),
],
),
),
),
),
);
}
}
class TempScreen extends StatefulWidget {
TempScreen({Key? key}) : super(key: key);
#override
State<TempScreen> createState() => _TempScreenState();
}
class _TempScreenState extends State<TempScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Temp screen"),
),
body: Column(
children: [
TextButton(
onPressed: (){
showDialog(
context: context,
builder: (BuildContext context) {
return TempDialog();
}
);
},
child: Text("Tap me"))
],
),
);
}
}
And this is the result:
As you see TextField that is at the bottom is not visible on focus - scrollview doesnt scroll to its position.
Could anyone say how to fix this issue. Please, note, that solution needs to support multiple TextFields (as I've said I have many of them).
EDIT 1
I tried to use scrollable positioned list. This is my code
import 'package:flutter/material.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class TempDialog extends StatefulWidget {
TempDialog({Key? key}) : super(key: key);
#override
State<TempDialog> createState() => _TempDialogState();
}
class _TempDialogState extends State<TempDialog> {
final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();
#override
Widget build(BuildContext context) {
return AlertDialog(
content: Container(
width: 300,
height: 500,
child: ScrollablePositionedList.builder(
padding: EdgeInsets.only(top: 10),
itemCount: 2,
physics: ClampingScrollPhysics(),
itemBuilder: (context, index) {
return Focus(
child: Padding(
padding: EdgeInsets.only(bottom: 500),
child: TextField(
key: ValueKey("_k" + index.toString()),
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.red,
filled: true
),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
//controller: textController,
),
),
onFocusChange: (hasFocus) {
if (hasFocus) {
// itemScrollController.jumpTo(index: index);
itemScrollController.scrollTo(
index: index,
duration: Duration(seconds: 2),
curve: Curves.easeInOutCubic);
}
} ,
);
},
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
),
),
);
}
}
class TempScreen extends StatefulWidget {
TempScreen({Key? key}) : super(key: key);
#override
State<TempScreen> createState() => _TempScreenState();
}
class _TempScreenState extends State<TempScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Temp screen"),
),
body: Column(
children: [
TextButton(
onPressed: (){
showDialog(
context: context,
builder: (BuildContext context) {
return TempDialog();
}
);
},
child: Text("Tap me"))
],
),
);
}
}
and this is the result:
As you see the problem is that when keyboard is shown it doesn't scroll to focused item.
Your code works absolutely fine on both devices. I have added a gesture detector to the Container since the textfields were multi-lined so there was no option to lower the keyboard in iOS. Here is the code that I have used
import 'package:flutter/material.dart';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:image/image.dart' as img;
void main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(home: TempScreen());
}
}
class TempDialog extends StatefulWidget {
TempDialog({Key? key}) : super(key: key);
#override
State<TempDialog> createState() => _TempDialogState();
}
class _TempDialogState extends State<TempDialog> {
#override
Widget build(BuildContext context) {
var textController = TextEditingController(text: "");
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return AlertDialog(
content: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
width: width,
height: height,
child: Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.purple,
filled: true),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
controller: textController,
),
SizedBox(
height: 90,
),
TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.green,
filled: true),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
controller: textController,
),
SizedBox(
height: 90,
),
TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.blue,
filled: true),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
controller: textController,
),
SizedBox(
height: 90,
),
TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.red,
filled: true),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
controller: textController,
),
SizedBox(
height: 90,
),
TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.yellow,
filled: true),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
controller: textController,
),
SizedBox(
height: 90,
),
TextField(
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.red,
filled: true),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
controller: textController,
),
],
),
),
),
),
),
);
}
}
class TempScreen extends StatefulWidget {
TempScreen({Key? key}) : super(key: key);
#override
State<TempScreen> createState() => _TempScreenState();
}
class _TempScreenState extends State<TempScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Temp screen"),
),
body: Column(
children: [
TextButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return TempDialog();
});
},
child: Text("Tap me"))
],
),
);
}
}
EDIT
You can create a key and assign it to the textfield and you can use this key and scroll to that widget's position like this.
final dataKey = GlobalKey();
TextField(
key: dataKey,
textAlign: TextAlign.left,
decoration: const InputDecoration(
contentPadding: EdgeInsets.all(10.0),
fillColor: Colors.red,
filled: true),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 2,
controller: textController,
onTap: () {
Scrollable.ensureVisible(dataKey.currentContext!);//here you can scroll to the respective widget referring the key.
},
),
Please note that if you have a lot of textfields, this may result in some performance issue.. But scrolling to the right widget will work.
I managed to achieve that (not by myself, but I can't recall where I found help) in a similar case.
My widget structure is: AlertDialog -> Container (for width setting) -> StatefulBuilder. The last one, after a bit of preparation, returns this:
return Form(
key: _formKey,
child: ScrollablePositionedList.builder(
padding: EdgeInsets.only(top: 10),
itemCount: childrenList.length,
itemBuilder: (context, index) => childrenList[index],
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
));
where
childrenList contains the list of widgets, most of them being TextFormField
itemBuilder just takes the items in order
itemScrollController is just final ItemScrollController itemScrollController = ItemScrollController();
itemPositionsListener is just final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();
I don't think that there's anything else involved in the "auto-scrolling" thing, but I wrote this a while ago, so let me know if something's missing.

Call a function whenever there is a change in Flutter

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

How to set Background image properly in to my code

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

The prefixIcon of TextField widget in flutter disappears on focusing TextField. How to solve?

Was just exploring flutter and got stuck. The prefixIcon disappears on clicking field and it appears back when focused out. How to solve this ? The code is as below. Tried removing the key of form. I want the icon to stay even if focused in or focused out. Is there any other property to set?
Couldn't be able to find a fix.
class _MyHomePageState extends State<MyHomePage> {
String _email = "";
String _password = "";
final _formKey = GlobalKey<FormState>();
final FocusNode _emailFocus = FocusNode();
final FocusNode _passwordFocus = FocusNode();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 50.0,vertical: 100.0),
decoration: BoxDecoration(color: Colors.white),
child:Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
focusNode: _emailFocus,
decoration: InputDecoration(
labelText: 'Username or email',
prefixIcon: Icon(Icons.person), //prefixIcon
focusedBorder: UnderlineInputBorder(),
hintText: "example#mail.com",
)
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
),
TextFormField(
obscureText: true,
focusNode: _passwordFocus,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock),
focusedBorder: UnderlineInputBorder(),
)
) ,
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
onPressed: () {
// Validate will return true if the form is valid, or false if
// the form is invalid.
if (_formKey.currentState.validate()) {
// Process data.
}
},
child: Text('Submit'),
),
),
],
),
)
)
);
}
}
The issue was that I had set the primary colour to white. So whenever the field was focused it was disappering as the background was also white. My bad.
the issue came to me when i add TextField to AppBar as title.
to fix this, just add color to icon.
e.g.
prefixIcon: Icon(Icons.person), //prefixIcon
should be replaced with
prefixIcon: Icon(Icons.person, color: Colors.black,), //prefixIcon
i post an issue, but no response yet.
this works fine for me
class MyHomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
String _email = "";
String _password = "";
final _formKey = GlobalKey<FormState>();
final FocusNode _emailFocus = FocusNode();
final FocusNode _passwordFocus = FocusNode();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('hi'),
),
body: Container(
padding: EdgeInsets.only(top: 50, left: 50, right: 50),
decoration: BoxDecoration(color: Colors.white),
child: Form(
key: _formKey,
child: ListView(
children: <Widget>[
TextFormField(
focusNode: _emailFocus,
decoration: InputDecoration(
labelText: 'Username or email',
prefixIcon: Icon(Icons.person), //prefixIcon
focusedBorder: UnderlineInputBorder(),
hintText: "example#mail.com",
)),
Padding(
padding: EdgeInsets.only(top: 20),
),
TextFormField(
obscureText: true,
focusNode: _passwordFocus,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock),
focusedBorder: UnderlineInputBorder(),
)),
Padding(
padding: EdgeInsets.only(top: 20),
child: RaisedButton(
onPressed: () {
// Validate will return true if the form is valid, or false if
// the form is invalid.
if (_formKey.currentState.validate()) {
// Process data.
}
},
child: Text('Submit'),
),
),
],
),
)));
}