我们在抖动中使用步进器,并且在我们尝试实现的示例中看到了奇怪的数据问题。当您输入“名字”文本框时,它不会立即输入,您必须执行多次,并且“名字”文本区域中也会显示该名字。非常奇怪的行为,我不确定我们何时发现此示例,也许不是一个好例子:)
import 'package:flutter/material.dart';
import 'package:validators/validators.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:lightbridge_mobile/models/user_step1_model .dart';
import 'package:lightbridge_mobile/screens/member/profile/step2.dart';
import 'package:lightbridge_mobile/models/user.dart';
class ProfileStep1 extends StatefulWidget {
final User user;
const ProfileStep1({Key key, this.user}) : super(key: key);
@override
State<StatefulWidget> createState() {
return new MyAppScreenMode(user: user);
}
}
class MyData {
String firstname = '';
String lastname = '';
String phone = '';
String email = '';
}
class MyAppScreenMode extends State<ProfileStep1> {
final User user;
MyAppScreenMode({@required this.user});
@override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.blueGrey
),
home: new Scaffold(
appBar: new AppBar(
backgroundColor: const Color.fromRGBO(1,89,99, 1.0),
title: Container(child: Row(children: <Widget>[
Icon(
FontAwesomeIcons.userPlus,
size: 25.0,
color: Colors.white,
),
new Text(' Create Account : Step 1 of 5'),
],
),
),
),
body: Container(
child: StepperBody(user: user),
decoration: BoxDecoration(
gradient: new LinearGradient(
colors: [Color.fromRGBO(1,89,99, 1.0),Color.fromRGBO(1,89,99, 1.0),],
begin: Alignment.bottomLeft,
end: Alignment.topRight
)
),
)
)
);
}
}
class StepperBody extends StatefulWidget {
final User user;
const StepperBody({Key key,@required this.user}) : super(key: key);
@override
_StepperBodyState createState() => new _StepperBodyState();
}
class _StepperBodyState extends State<StepperBody> {
int currStep = 0;
static var _focusNode = new FocusNode();
GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
static MyData data = new MyData();
@override
void initState() {
super.initState();
_focusNode.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
}
@override
void dispose() {
_focusNode.dispose();
super.dispose();
}
List<Step> steps = [
new Step(
title: const Text('First Name', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 19.0 )),
isActive: true,
state: StepState.indexed,
content: new TextFormField(
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
onSaved: (String fnvalue) {
data.firstname = fnvalue;
},
maxLines: 1,
validator: (fnvalue) {
if (fnvalue.isEmpty || fnvalue.length < 1) {
return 'Please enter first name';
}
},
decoration: new InputDecoration(
labelText: 'Enter your first name',
icon: const Icon(Icons.person, color: Colors.white),
labelStyle:
new TextStyle(decorationStyle: TextDecorationStyle.solid,color: Colors.white, fontSize: 16.0))
),
),
new Step(
title: const Text('Last Name', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 19.0 )),
isActive: false,
state: StepState.indexed,
content: new TextFormField(
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
onSaved: (String lnvalue) {
data.lastname = lnvalue;
},
maxLines: 1,
validator: (lnvalue) {
if (lnvalue.isEmpty || lnvalue.length < 1) {
return 'Please enter last name';
}
},
decoration: new InputDecoration(
labelText: 'Enter your last name',
icon: const Icon(Icons.person, color: Colors.white),
labelStyle:
new TextStyle(decorationStyle: TextDecorationStyle.solid)),
)),
new Step(
title: const Text('Phone',style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 19.0 )),
//subtitle: const Text('Subtitle'),
isActive: false,
//state: StepState.editing,
state: StepState.indexed,
content: new TextFormField(
keyboardType: TextInputType.phone,
autocorrect: false,
validator: (value) {
if (value.isEmpty || value.length < 10) {
return 'Please enter valid number';
}
},
onSaved: (String value) {
data.phone = value;
},
maxLines: 1,
decoration: new InputDecoration(
labelText: 'Enter your number',
icon: const Icon(Icons.phone, color: Colors.white),
labelStyle:
new TextStyle(decorationStyle: TextDecorationStyle.solid, color: Colors.white, fontSize: 16.0)),
)),
new Step(
title: const Text('Email', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 19.0 )),
// subtitle: const Text('Subtitle'),
isActive: false,
state: StepState.indexed,
// state: StepState.disabled,
content: new TextFormField(
keyboardType: TextInputType.emailAddress,
style: new TextStyle(color: Colors.white),
autocorrect: false,
validator: (value) {
if (value.isEmpty || !value.contains('@')) {
return 'Please enter valid email';
}
},
onSaved: (String value) {
data.email = value;
},
maxLines: 1,
decoration: new InputDecoration(
labelText: 'Enter your email',
hintText: 'Enter a email address',
icon: const Icon(Icons.email, color: Colors.white),
labelStyle:
new TextStyle(decorationStyle: TextDecorationStyle.solid, color: Colors.white, fontSize: 16.0))),
),
];
@override
Widget build(BuildContext context) {
void showSnackBarMessage(String message,
[MaterialColor color = Colors.red]) {
Scaffold
.of(context)
.showSnackBar(new SnackBar(content: new Text(message)));
}
void _submitDetails() {
final FormState formState = _formKey.currentState;
if (!formState.validate()) {
showSnackBarMessage('Please enter correct data');
} else {
formState.save();
// HERE
insertUserStep1(data.firstname, data.lastname, data.email, data.phone);
}
}
return new Container(
child: new Form(
key: _formKey,
child: new ListView(children: <Widget>[
new Stepper(
steps: steps,
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
// else {
// Scaffold
// .of(context)
// .showSnackBar(new SnackBar(content: new Text('$currStep')));
// if (currStep == 1) {
// print('First Step');
// print('object' + FocusScope.of(context).toStringDeep());
// }
// }
});
},
onStepCancel: () {
setState(() {
if (currStep > 0) {
currStep = currStep - 1;
} else {
currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
Container(
margin: EdgeInsets.all(10.0),
child: OutlineButton(
child: Text('Tap to Continue'), textColor: Colors.white,
shape: new RoundedRectangleBorder(borderRadius: new BorderRadius.circular(30.0)),
onPressed: _submitDetails,
)
// Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ProfileStep1()));
),
] ),
));
}
Future<void> insertUserStep1(String firstname, String lastname, String email, String cell ) async
{
final response =
await http.post('http://url/api/UserStep1',
headers: {"Content-Type": "application/json",
'Accept': 'application/json',},
body: json.encode({'firstname' : firstname,'lastname' : lastname , 'email' : email, 'cell': cell}));
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
UserStep1Model _user;
_user = UserStep1Model.fromJson(json.decode(response.body));
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ProfileStep2(userID: _user.userId)));
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load user');
}
}
}
答案 0 :(得分:0)
您可以让名字TextFormField
和姓氏TextFormField
使用不同的focusNode
代码段
content: new TextFormField(
focusNode: _focusNode,
keyboardType: TextInputType.text,
content: new TextFormField(
focusNode: _focusNodeLastName,
keyboardType: TextInputType.text,
工作演示
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ProfileStep1(user: User()),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ProfileStep1 extends StatefulWidget {
final User user;
const ProfileStep1({Key key, this.user}) : super(key: key);
@override
State<StatefulWidget> createState() {
return new MyAppScreenMode(user: user);
}
}
class User {}
class MyData {
String firstname = '';
String lastname = '';
String phone = '';
String email = '';
}
class MyAppScreenMode extends State<ProfileStep1> {
final User user;
MyAppScreenMode({@required this.user});
@override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(primarySwatch: Colors.blueGrey),
home: new Scaffold(
appBar: new AppBar(
backgroundColor: const Color.fromRGBO(1, 89, 99, 1.0),
title: Container(
child: Row(
children: <Widget>[
Icon(
FontAwesomeIcons.userPlus,
size: 25.0,
color: Colors.white,
),
new Text(' Create Account : Step 1 of 5'),
],
),
),
),
body: Container(
child: StepperBody(user: user),
decoration: BoxDecoration(
gradient: new LinearGradient(colors: [
Color.fromRGBO(1, 89, 99, 1.0),
Color.fromRGBO(1, 89, 99, 1.0),
], begin: Alignment.bottomLeft, end: Alignment.topRight)),
)));
}
}
class StepperBody extends StatefulWidget {
final User user;
const StepperBody({Key key, @required this.user}) : super(key: key);
@override
_StepperBodyState createState() => new _StepperBodyState();
}
class _StepperBodyState extends State<StepperBody> {
int currStep = 0;
static var _focusNode = new FocusNode();
static var _focusNodeLastName = new FocusNode();
GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
static MyData data = new MyData();
@override
void initState() {
super.initState();
_focusNode.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
_focusNodeLastName.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
}
@override
void dispose() {
_focusNode.dispose();
_focusNodeLastName.dispose();
super.dispose();
}
List<Step> steps = [
new Step(
title: const Text('First Name',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 19.0)),
isActive: true,
state: StepState.indexed,
content: new TextFormField(
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
onSaved: (String fnvalue) {
data.firstname = fnvalue;
},
maxLines: 1,
validator: (fnvalue) {
if (fnvalue.isEmpty || fnvalue.length < 1) {
return 'Please enter first name';
}
},
decoration: new InputDecoration(
labelText: 'Enter your first name',
icon: const Icon(Icons.person, color: Colors.white),
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid,
color: Colors.white,
fontSize: 16.0))),
),
new Step(
title: const Text('Last Name',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 19.0)),
isActive: false,
state: StepState.indexed,
content: new TextFormField(
focusNode: _focusNodeLastName,
keyboardType: TextInputType.text,
autocorrect: false,
onSaved: (String lnvalue) {
data.lastname = lnvalue;
},
maxLines: 1,
validator: (lnvalue) {
if (lnvalue.isEmpty || lnvalue.length < 1) {
return 'Please enter last name';
}
},
decoration: new InputDecoration(
labelText: 'Enter your last name',
icon: const Icon(Icons.person, color: Colors.white),
labelStyle:
new TextStyle(decorationStyle: TextDecorationStyle.solid)),
)),
new Step(
title: const Text('Phone',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 19.0)),
//subtitle: const Text('Subtitle'),
isActive: false,
//state: StepState.editing,
state: StepState.indexed,
content: new TextFormField(
keyboardType: TextInputType.phone,
autocorrect: false,
validator: (value) {
if (value.isEmpty || value.length < 10) {
return 'Please enter valid number';
}
},
onSaved: (String value) {
data.phone = value;
},
maxLines: 1,
decoration: new InputDecoration(
labelText: 'Enter your number',
icon: const Icon(Icons.phone, color: Colors.white),
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid,
color: Colors.white,
fontSize: 16.0)),
)),
new Step(
title: const Text('Email',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 19.0)),
// subtitle: const Text('Subtitle'),
isActive: false,
state: StepState.indexed,
// state: StepState.disabled,
content: new TextFormField(
keyboardType: TextInputType.emailAddress,
style: new TextStyle(color: Colors.white),
autocorrect: false,
validator: (value) {
if (value.isEmpty || !value.contains('@')) {
return 'Please enter valid email';
}
},
onSaved: (String value) {
data.email = value;
},
maxLines: 1,
decoration: new InputDecoration(
labelText: 'Enter your email',
hintText: 'Enter a email address',
icon: const Icon(Icons.email, color: Colors.white),
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid,
color: Colors.white,
fontSize: 16.0))),
),
];
@override
Widget build(BuildContext context) {
void showSnackBarMessage(String message,
[MaterialColor color = Colors.red]) {
Scaffold.of(context)
.showSnackBar(new SnackBar(content: new Text(message)));
}
void _submitDetails() {
final FormState formState = _formKey.currentState;
if (!formState.validate()) {
showSnackBarMessage('Please enter correct data');
} else {
formState.save();
// HERE
//insertUserStep1(data.firstname, data.lastname, data.email, data.phone);
}
}
return new Container(
child: new Form(
key: _formKey,
child: new ListView(children: <Widget>[
new Stepper(
steps: steps,
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
// else {
// Scaffold
// .of(context)
// .showSnackBar(new SnackBar(content: new Text('$currStep')));
// if (currStep == 1) {
// print('First Step');
// print('object' + FocusScope.of(context).toStringDeep());
// }
// }
});
},
onStepCancel: () {
setState(() {
if (currStep > 0) {
currStep = currStep - 1;
} else {
currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
Container(
margin: EdgeInsets.all(10.0),
child: OutlineButton(
child: Text('Tap to Continue'),
textColor: Colors.white,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
onPressed: _submitDetails,
)
// Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ProfileStep1()));
),
]),
));
}
}