所以我有一个这样的表单屏幕(带有自己的支架):
class InputForm extends StatelessWidget {
final Receipt initialReceipt;
InputForm({this.initialReceipt}){
print("InputForm() called");
}
@override
Widget build(BuildContext context) {
return BlocProvider(
bloc: InputFormBloc(),
child: InputFromWidget(initialReceipt: initialReceipt),
);
}
}
class InputFromWidget extends StatelessWidget {
final Receipt initialReceipt;
InputFromWidget({this.initialReceipt}){
print("InputFromWidget() called");
}
@override
Widget build(BuildContext context) {
return Scaffold(...........);
}
我有这样的根Widget:
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
child: MaterialApp(
title: 'Takefin',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.purple,
),
//home: InputForm(),
home: DashboardWidget(),
),
bloc: TakeFinBloc(),
);
}
}
它何时按计划运作?
我设置的时间
home: InputForm()
,
即使我单击任意位置并且UI发生更改(下拉或单击输入字段)
print("InputForm() called");
print("InputFromWidget() called");
仅被调用一次。
但是当我设置
home: DashboardWidget(),
然后在DashboardWidget上单击一个按钮,我这样做是:
MaterialPageRoute(builder: (context) => InputForm())
然后,当我在InputForm屏幕上的某个位置单击以更改小部件时(例如,展开下拉菜单,在字段中键入内容)
print("InputForm() called");
print("InputFromWidget() called");
每次点击都会导致布局发生变化。
这是正常行为吗?
如果是,最好的存储InputFromWidget状态以避免从头开始创建状态的方法是什么?
答案 0 :(得分:0)
是的,这是正常现象。您必须使用StatefulWidget存储InputFromWidget的状态,以避免从头开始创建它。 从下面的注册屏幕示例中,您可以了解如何管理InputFromWidget的状态。
sign_up_screen.dart
class SignUpScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _SignUpScreenState();
}
}
class _SignUpScreenState extends State<SignUpScreen> {
@override
Widget build(BuildContext context) {
// TODO: implement build
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))),
),
);
}
}