Yes, this is normal behavior.you have to use StatefulWidget store the state of InputFromWidget to avoid recreating it from start.
From below signup screen example you can get idea how you can manage state for InputFromWidget.
sign_up_screen.dart
class SignUpScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _SignUpScreenState();
}
}
class _SignUpScreenState extends State<SignUpScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("SignUp"),
),
body: Container(
padding: EdgeInsets.all(15.0),
color: Colors.white,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
SignUpFormWidget(),
SocialLoginWidget(),
],
),
),
),
);
}
}
sing_up_form_widget.dart
class SignUpFormWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _SignUpFormWidgetState();
}
}
class _SignUpFormWidgetState extends State<SignUpFormWidget> {
final _formKey = GlobalKey<FormState>();
var _userNameController = TextEditingController(text: "");
var _userEmailController = TextEditingController(text: "");
var _userPasswordController = TextEditingController(text: "");
var _emailFocusNode = FocusNode();
var _passwordFocusNode = FocusNode();
bool _isPasswordVisible = true;
bool _autoValidate = false;
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
autovalidate: _autoValidate,
child: Column(
children: <Widget>[
_buildUserNameField(context),
_buildEmailField(context),
_buildPasswordField(context),
_buildTermsWidget(context),
_buildSignUpButton(context),
],
),
);
}
Widget _buildUserNameField(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 5),
child: TextFormField(
controller: _userNameController,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(_emailFocusNode);
},
validator: (value) => _userNameValidation(value),
decoration: CommonStyles.textFormFieldStyle("User Name", ""),
),
);
}
String _userNameValidation(String value) {
if (value.isEmpty) {
return "Please enter valid user name";
} else {
return null;
}
}
Widget _buildEmailField(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 5),
child: TextFormField(
controller: _userEmailController,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(_passwordFocusNode);
},
validator: (value) => _emailValidation(value),
decoration: CommonStyles.textFormFieldStyle("Email", ""),
),
);
}
String _emailValidation(String value) {
bool emailValid =
RegExp(r"^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(value);
if (!emailValid) {
return "Enter valid email address";
} else {
return null;
}
}
Widget _buildPasswordField(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 5),
child: TextFormField(
controller: _userPasswordController,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(_emailFocusNode);
},
validator: (value) => _userNameValidation(value),
obscureText: _isPasswordVisible,
decoration: InputDecoration(
labelText: "Password",
hintText: "",
labelStyle: TextStyle(color: Colors.black),
alignLabelWithHint: true,
contentPadding: EdgeInsets.symmetric(vertical: 5),
suffixIcon: IconButton(
icon: Icon(
_isPasswordVisible ? Icons.visibility_off : Icons.visibility,
color: Colors.black,
),
onPressed: () {
setState(() {
_isPasswordVisible = !_isPasswordVisible;
});
}),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
),
);
}
Widget _buildTermsWidget(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
child: GestureDetector(
onTap: (){_openTermsInWeb();},
child: RichText(
text: new TextSpan(
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
),
children: <TextSpan>[
TextSpan(
text: 'Terms of use',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
TextSpan(
text: ' and ',
style: TextStyle(
color: Colors.black54, fontWeight: FontWeight.w500),
),
TextSpan(
text: 'Privacy policy',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
],
),
),
),
);
}
Widget _buildSignUpButton(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 15.0),
width: double.infinity,
child: RaisedButton(
color: Colors.black,
onPressed: () {
_signUpProcess(context);
},
child: Text(
"Sign Up",
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w800),
),
),
);
}
void _signUpProcess(BuildContext context) {
var validate = _formKey.currentState.validate();
if (validate) {
showDialog(
context: context,
builder: (BuildContext ctx) {
return AlertDialog(
title: Text("Sign Up Success."),
actions: <Widget>[
FlatButton(
onPressed: () {
_clearAllFields();
Navigator.of(context).pop();
},
child: Text("Close"))
],
);
});
} else {
setState(() {
_autoValidate = true;
});
}
}
void _clearAllFields() {
setState(() {
_userNameController = TextEditingController(text: "");
_userEmailController = TextEditingController(text: "");
_userPasswordController = TextEditingController(text: "");
});
}
_openTermsInWeb( ) async {
const url = 'https://www.solutionanalysts.com/terms-use/';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
}
social_login_widget.dart
class SocialLoginWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
children: <Widget>[
_buildSocialLoginTextWidget(context),
Row(
children: <Widget>[
__buildFacebookButtonWidget(context),
__buildTwitterButtonWidget(context)
],
)
],
);
}
Widget _buildSocialLoginTextWidget(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
child: RichText(
text: new TextSpan(
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
),
children: <TextSpan>[
TextSpan(
text: 'Or sign up with social account',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
],
),
),
);
}
Widget __buildTwitterButtonWidget(BuildContext context) {
return Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: RaisedButton(
color: Color.fromRGBO(29, 161, 242, 1.0),
child: Image.asset(
"assets/images/ic_twitter.png",
width: 25,
height: 25,
),
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0))),
),
);
}
Widget __buildFacebookButtonWidget(BuildContext context) {
return Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: RaisedButton(
color: Color.fromRGBO(42, 82, 151, 1.0),
child: Image.asset(
"assets/images/ic_fb.png",
width: 35,
height: 35,
),
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0))),
),
);
}
}