#flutter #flutter-web
Вопрос:
Я создал простую веб-страницу, на которой у меня есть две кнопки: одна для добавления донора, а другая для перечисления доноров. При нажатии каждой кнопки я хочу, чтобы открывались соответствующие страницы.
Я нажимаю кнопку «Добавить донора», заполняю форму и нажимаю «Отправить». Затем я нажимаю «Список доноров» и возвращаюсь к «Добавить донора», и при нажатии на поле » Имя » я получаю следующую ошибку при запуске этого в браузере Chrome.
Error: A FocusNode was used after being disposed.
Once you have called dispose() on a FocusNode, it can no longer be used.
at Object.throw_ [as throw] (http://localhost:62365/dart_sdk.js:5334:11)
at http://localhost:62365/packages/flutter/src/foundation/change_notifier.dart.lib.js:83:21
at focus_manager.FocusNode.new.[_debugAssertNotDisposed] (http://localhost:62365/packages/flutter/src/foundation/change_notifier.dart.lib.js:86:25)
at focus_manager.FocusNode.new.notifyListeners (http://localhost:62365/packages/flutter/src/foundation/change_notifier.dart.lib.js:113:51)
at focus_manager.FocusNode.new.[_notify] (http://localhost:62365/packages/flutter/src/widgets/widget_span.dart.lib.js:47534:12)
at focus_manager.FocusManager.new.[_applyFocusChange] (http://localhost:62365/packages/flutter/src/widgets/widget_span.dart.lib.js:48310:26)
at Object._microtaskLoop (http://localhost:62365/dart_sdk.js:39176:13)
at _startMicrotaskLoop (http://localhost:62365/dart_sdk.js:39182:13)
at http://localhost:62365/dart_sdk.js:34689:9
Это мой фрагмент кода
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
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
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
BloodDonationPage(),
),
);
},
child: Scaffold(
body: Center(
child: Container(
width: 200,
height: 100,
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side:
BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Center(
child: Text(
"Blood Donation",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
)),
),
),
),
),
);
}
}
class BloodDonationPage extends StatefulWidget {
@override
_BloodDonationPageState createState() => _BloodDonationPageState();
}
class _BloodDonationPageState extends State<BloodDonationPage> {
bool _addButton = false;
bool _listButton = false;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 60,
//width: 600,
child: Card(
color: Colors.pink[50],
shadowColor: Colors.pink,
elevation: 20,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
GestureDetector(
onTap: () {
setState(() {
_addButton = true;
_listButton = false;
});
},
child: Padding(
padding: const EdgeInsets.only(left: 60, right: 30.0),
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side:
BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
"Add Donor",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold),
)),
),
),
),
),
GestureDetector(
onTap: () {
setState(() {
_addButton = false;
_listButton = true;
});
},
child: Padding(
padding: const EdgeInsets.only(left: 60, right: 30.0),
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
"List Donors",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold),
)),
),
),
),
),
],
),
),
),
_addButton ? Flexible(child: BloodDonorDetailPage()) : SizedBox.shrink(),
_listButton ? Flexible(child: ListBloodDonorPage()) : SizedBox.shrink(),
],
);
}
}
class BloodDonorDetailPage extends StatefulWidget {
@override
_BloodDonorDetailPageState createState() => _BloodDonorDetailPageState();
}
class _BloodDonorDetailPageState extends State<BloodDonorDetailPage> {
final _formKey = GlobalKey<FormBuilderState>();
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(30.0),
child: FormBuilder(
autovalidateMode: AutovalidateMode.disabled,
key: _formKey,
child: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FormBuilderTextField(
autofocus: true,
name: 'name',
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.maxLength(context, 50),
]),
decoration: InputDecoration(labelText: 'Name'),
),
FormBuilderTextField(
name: 'phone',
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.minLength(context, 10),
FormBuilderValidators.maxLength(context, 10),
FormBuilderValidators.numeric(context,
errorText: 'Mobile No should be 10 digits')
]),
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'Phone'),
),
FormBuilderChoiceChip(
name: 'gender',
elevation: 10,
selectedColor: Colors.white,
disabledColor: Colors.black12,
alignment: WrapAlignment.spaceAround,
options: ['M', 'F']
.map((value) => FormBuilderFieldOption(
value: value,
child: (value == 'M')
? Text('Male')
: Text('Female'),
))
.toList(),
decoration: InputDecoration(labelText: 'Gender'),
),
FormBuilderChoiceChip(
name: 'bloodGroup',
elevation: 10,
selectedColor: Colors.white,
disabledColor: Colors.black12,
alignment: WrapAlignment.spaceAround,
options: ['A ','O ']
.map((value) => FormBuilderFieldOption(value: value))
.toList(),
decoration: InputDecoration(labelText: 'Blood Group'),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
color: Theme.of(context).accentColor,
child: Text('Submit',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
//print(_formKey.currentState.mounted);
Map<String, dynamic> _donorMap;
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
//print(_formKey.currentState.value);
_donorMap = {
..._formKey.currentState.value,
'createdDate': DateTime.now()
};
print(_donorMap);
/*await BloodDonorsController()
.saveBloodDonors(widget.mode!, _donorMap);*/
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Add Donor Successful'),
),
);
_formKey.currentState.reset();
//FocusScope.of(context).requestFocus(focusNode);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Validation Failed'),
),
);
}
},
),
SizedBox(width: 20),
MaterialButton(
color: Theme.of(context).accentColor,
child: Text(
"Reset",
style: TextStyle(color: Colors.white),
),
onPressed: () {
_formKey.currentState.reset();
},
),
],
),
)
],
),
),
),
);
}
}
class ListBloodDonorPage extends StatefulWidget {
@override
_ListBloodDonorPageState createState() => _ListBloodDonorPageState();
}
class _ListBloodDonorPageState extends State<ListBloodDonorPage> {
@override
Widget build(BuildContext context) {
return Container(child: Text('Display List of Donors'),);
}
}
В чем здесь проблема?
Кто-нибудь может мне помочь, пожалуйста?
Ответ №1:
Я смог, наконец, решить эту проблему, преобразовав виджеты с отслеживанием состояния в методы и добавив виджет Видимость для отображения виджета с сохранением состояния, как показано ниже.
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
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
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
BloodDonationPage(),
),
);
},
child: Scaffold(
body: Center(
child: Container(
width: 200,
height: 100,
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side:
BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Center(
child: Text(
"Blood Donation",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
)),
),
),
),
),
);
}
}
class BloodDonationPage extends StatefulWidget {
@override
_BloodDonationPageState createState() => _BloodDonationPageState();
}
class _BloodDonationPageState extends State<BloodDonationPage> {
bool _addButton = false;
bool _listButton = false;
final _formKey = GlobalKey<FormBuilderState>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 60,
//width: 600,
child: Card(
color: Colors.pink[50],
shadowColor: Colors.pink,
elevation: 20,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
GestureDetector(
onTap: () {
setState(() {
_addButton = true;
_listButton = false;
});
},
child: Padding(
padding: const EdgeInsets.only(left: 60, right: 30.0),
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side:
BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
"Add Donor",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold),
)),
),
),
),
),
GestureDetector(
onTap: () {
setState(() {
_addButton = false;
_listButton = true;
});
},
child: Padding(
padding: const EdgeInsets.only(left: 60, right: 30.0),
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
"List Donors",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold),
)),
),
),
),
),
],
),
),
),
Visibility(visible: _addButton, maintainState: true,child: buildAdd()),
Visibility(visible: _listButton ,child: buildList()),
],
),
);
}
Widget buildList() => Container(child: Text('Display List of Donors'),);
Widget buildAdd() => Padding(
padding: const EdgeInsets.all(30.0),
child: Column( children: [ FormBuilder(
autovalidateMode: AutovalidateMode.disabled,
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FormBuilderTextField(
autofocus: true,
name: 'name',
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.maxLength(context, 50),
]),
decoration: InputDecoration(labelText: 'Name'),
),
FormBuilderTextField(
name: 'phone',
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.minLength(context, 10),
FormBuilderValidators.maxLength(context, 10),
FormBuilderValidators.numeric(context,
errorText: 'Mobile No should be 10 digits')
]),
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'Phone'),
),
FormBuilderChoiceChip(
name: 'gender',
elevation: 10,
selectedColor: Colors.white,
disabledColor: Colors.black12,
alignment: WrapAlignment.spaceAround,
options: ['M', 'F']
.map((value) => FormBuilderFieldOption(
value: value,
child: (value == 'M')
? Text('Male')
: Text('Female'),
))
.toList(),
decoration: InputDecoration(labelText: 'Gender'),
),
FormBuilderChoiceChip(
name: 'bloodGroup',
elevation: 10,
selectedColor: Colors.white,
disabledColor: Colors.black12,
alignment: WrapAlignment.spaceAround,
options: ['A ','O ']
.map((value) => FormBuilderFieldOption(value: value))
.toList(),
decoration: InputDecoration(labelText: 'Blood Group'),
),
],),),
SizedBox(height: 100,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
color: Theme.of(context).accentColor,
child: Text('Submit',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
//print(_formKey.currentState.mounted);
Map<String, dynamic> _donorMap;
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
//print(_formKey.currentState.value);
_donorMap = {
..._formKey.currentState.value,
'createdDate': DateTime.now()
};
print(_donorMap);
/*await BloodDonorsController()
.saveBloodDonors(widget.mode!, _donorMap);*/
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Add Donor Successful'),
),
);
_formKey.currentState.reset();
//FocusScope.of(context).requestFocus(focusNode);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Validation Failed'),
),
);
}
},
),
SizedBox(width: 20),
MaterialButton(
color: Theme.of(context).accentColor,
child: Text(
"Reset",
style: TextStyle(color: Colors.white),
),
onPressed: () {
_formKey.currentState.reset();
},
),
],
)
],
),
);
}