flutter - 在小部件树中检测到重复的 GlobalKey。在表单验证中
问题描述
当我当时使用表单验证时,我在小部件树中检测到错误 Duplicate GlobalKey。
有人可以在下面的代码中解释如何创建重复键吗?是因为底片吗?我试图创建不同的底部小部件作为 _tempFormBody 代码
class CreateProfile extends StatefulWidget {
@override
_CreateProfileState createState() => _CreateProfileState();
}
class _CreateProfileState extends State<CreateProfile>
with AutomaticKeepAliveClientMixin {
TextEditingController petname = TextEditingController();
TextEditingController hisage = TextEditingController();
TextEditingController templevel = TextEditingController();
final _formKey = GlobalKey<FormState>();
bool pressAttention = false;
bool pressAttention2 = false;
// Todo image picker
File _image;
final picker = ImagePicker();
var fileSelected = false;
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
fileSelected = true;
_image = File(pickedFile.path);
} else {
print('No image selected.');
fileSelected = false;
}
});
}
@override
void initState() {
super.initState();
_tempFormBody();
}
//
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_formKey.currentState.dispose();
}
var selectedtemperament = "";
_selectTemperament() {
List temperament = [
"Stable",
"Confident",
"Aggressive",
"Friendly",
"Protective"
];
return showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 400,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25), topRight: Radius.circular(25)),
color: Colors.white),
child: Column(
children: [
SizedBox(
height: 30,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Temperament Level",
textAlign: TextAlign.left,
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.w700),
),
IconButton(
icon: Icon(Icons.close),
onPressed: () => Navigator.pop(context),
),
],
),
),
ListView.builder(
shrinkWrap: true,
itemCount: temperament.length,
itemBuilder: (BuildContext context, int index) {
var temp = temperament[index];
return Column(
children: [
ListTile(
title: InkWell(
onTap: () {
print("$temp");
setState(() {
selectedtemperament = temp;
});
Navigator.pop(context);
},
child: Text(
'$temp',
style: TextStyle(fontWeight: FontWeight.w500),
)),
),
],
);
},
),
],
),
);
},
);
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
// key: globalKey,
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 52,
),
Row(
children: [
SizedBox(
width: 10,
),
Padding(
padding: const EdgeInsets.only(right: 90),
child: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(
Icons.arrow_back_ios,
color: Colors.white,
)),
),
Row(
children: [
Container(
color: Colors.white,
height: 3,
width: 28,
),
SizedBox(
width: 6,
),
Container(
color: Colors.grey,
height: 3,
width: 28,
),
SizedBox(
width: 6,
),
Container(
color: Colors.grey,
height: 3,
width: 28,
),
],
)
],
),
Text(
"STEP 1 OF 3",
style: TextStyle(
color: Color(0xffBCB6D1), fontSize: 10, letterSpacing: 0.63),
),
SizedBox(
height: 6,
),
Text(
"Your dog's profile",
style: GoogleFonts.montserrat(
textStyle: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.w700,
letterSpacing: -0.4)),
)
],
),
),
bottomSheet: Container(
width: double.infinity,
height: MediaQuery.of(context).size.height * 0.67,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25), topRight: Radius.circular(25)),
color: Colors.white),
child: Padding(
padding: const EdgeInsets.only(left: 2, right: 2),
child: _tempFormBody(),
),
),
floatingActionButton: InkWell(
onTap: () {
print(_image);
getImage();
},
child: Container(
height: 126,
width: 126,
decoration: BoxDecoration(
image: fileSelected
? DecorationImage(image: FileImage(_image), fit: BoxFit.cover)
: null,
borderRadius: BorderRadius.circular(100),
color: Color(0xffEAE8F2),
),
child: fileSelected
? null
: Icon(
Icons.add_a_photo_outlined,
color: Colors.grey,
size: 50,
)),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
_tempFormBody(){
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 90,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FlatButton(
minWidth: 126,
height: 36,
onPressed: () {
setState(() {
pressAttention = !pressAttention;
pressAttention2 = false;
});
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
FontAwesomeIcons.mars,
color: pressAttention
? Color(0xffFF4AAB)
: Color(0xff9891B4),
),
SizedBox(
width: 5,
),
Text(
"Male",
style: GoogleFonts.montserrat(
textStyle: TextStyle(
color: pressAttention
? Color(0xffFF4AAB)
: Color(0xff9891B4),
fontWeight: FontWeight.w600,
fontSize: 14)),
)
],
),
color: pressAttention
? Color(0xffFFECF6)
: Colors.transparent,
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1,
color: pressAttention
? Color(0xffFF4AAB)
: Color(0xff9891B4)),
borderRadius: BorderRadius.circular(66.0),
),
),
SizedBox(
width: 15,
),
FlatButton(
minWidth: 126,
height: 36,
onPressed: () {
setState(() {
pressAttention2 = !pressAttention2;
pressAttention = false;
});
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
FontAwesomeIcons.venus,
color: pressAttention2
? Color(0xffFF4AAB)
: Color(0xff9891B4),
),
SizedBox(
width: 5,
),
Text(
"Female",
style: GoogleFonts.montserrat(
textStyle: TextStyle(
fontSize: 14,
color: pressAttention2
? Color(0xffFF4AAB)
: Color(0xff9891B4)),
fontWeight: FontWeight.w600),
)
],
),
color: pressAttention2
? Color(0xffFFECF6)
: Colors.transparent,
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1,
color: pressAttention2
? Color(0xffFF4AAB)
: Color(0xff9891B4)),
borderRadius: BorderRadius.circular(66.0),
),
),
],
),
SizedBox(
height: 5,
),
Container(
width: 305,
child: TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter pets name';
}
return null;
},
controller: petname,
decoration: InputDecoration(
labelText: "Pets Name",
hintStyle: TextStyle(color: Colors.grey),
focusColor: Colors.grey,
labelStyle:
TextStyle(color: Color(0xffBCB6D1), fontSize: 14),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff1E163E))),
hintText: "eg:- bruno"),
),
),
SizedBox(
height: 20,
),
Container(
width: 305,
child: TextFormField(
validator: (value) {
int a = int.parse(value);
if (a < 1) {
return 'Number cant be zero';
} else if (value.isEmpty) {
return 'Enter age';
}
return null;
},
controller: hisage,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
], // Only nu
decoration: InputDecoration(
labelText: "His Age",
labelStyle:
TextStyle(color: Color(0xffBCB6D1), fontSize: 14),
hintStyle: TextStyle(color: Colors.grey),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff1E163E))),
border: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xffBCB6D1))),
hintText: "His Age"),
),
),
SizedBox(
height: 20,
),
Container(
width: 305,
child: TextFormField(
onTap: () => _selectTemperament(),
focusNode: AlwaysDisabledFocusNode(),
initialValue: "$selectedtemperament",
style: TextStyle(fontSize: 16, color: Color(0xff4D466A)),
decoration: InputDecoration(
labelStyle:
TextStyle(color: Color(0xffBCB6D1), fontSize: 14),
suffixIcon: IconButton(
icon: Icon(
FontAwesomeIcons.chevronDown,
color: Color(0xffBCB6D1),
size: 16,
),
onPressed: null,
),
labelText: "Temperament level",
hintStyle: TextStyle(color: Colors.grey),
border: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xffBCB6D1))),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff1E163E))),
)),
),
Expanded(child: Container()),
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: CustomButton(
text: "CONTINUE",
onPressed: () {
if (_formKey.currentState.validate()) {
Navigator.pushNamed(context, '/selectbreed');
}
},
),
)
],
),
);
}
@override
bool get wantKeepAlive => true;
}
class AlwaysDisabledFocusNode extends FocusNode {
@override
bool get hasFocus => false;
}
错误
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
Duplicate GlobalKey detected in widget tree.
The following GlobalKey was specified multiple times in the widget tree. This will lead to parts of the widget tree being truncated unexpectedly, because the second time a key is seen, the previous instance is moved to the new location. The key was:
- [LabeledGlobalKey<FormState>#0229e]
This was determined by noticing that after the widget with the above global key was moved out of its previous parent, that previous parent never updated during this frame, meaning that it either did not update at all or updated before the widget was moved, in either case implying that it still thinks that it should have a child with that global key.
The specific parent that did not update after having one or more children forcibly removed due to GlobalKey reparenting is:
- Padding(padding: EdgeInsets(2.0, 0.0, 2.0, 0.0), dependencies: [Directionality], renderObject: RenderPadding#ed2cb)
A GlobalKey can only be specified on one widget at a time in the widget tree.
When the exception was thrown, this was the stack:
#0 BuildOwner.finalizeTree.<anonymous closure> (package:flutter/src/widgets/framework.dart:2881:15)
#1 BuildOwner.finalizeTree (package:flutter/src/widgets/framework.dart:2906:8)
#2 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:915:18)
#3 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:302:5)
#4 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
请为此提供帮助,在此先感谢
解决方案
您可以在下面复制粘贴运行完整代码
在这种情况下,要修复错误,您可以将bottomSheet
逻辑移动到StatefulWidget
代码片段
bottomSheet: YourBottomSheet(),
...
class YourBottomSheet extends StatefulWidget {
@override
_YourBottomSheetState createState() => _YourBottomSheetState();
}
class _YourBottomSheetState extends State<YourBottomSheet> {
TextEditingController petname = TextEditingController();
TextEditingController hisage = TextEditingController();
TextEditingController templevel = TextEditingController();
final _formKey = GlobalKey<FormState>();
bool pressAttention = false;
bool pressAttention2 = false;
...
工作演示
完整代码
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:image_picker/image_picker.dart';
class CreateProfile extends StatefulWidget {
@override
_CreateProfileState createState() => _CreateProfileState();
}
class _CreateProfileState extends State<CreateProfile>
with AutomaticKeepAliveClientMixin {
// Todo image picker
File _image;
final picker = ImagePicker();
var fileSelected = false;
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
fileSelected = true;
_image = File(pickedFile.path);
} else {
print('No image selected.');
fileSelected = false;
}
});
}
@override
void initState() {
super.initState();
//_tempFormBody();
}
//
@override
void dispose() {
// TODO: implement dispose
super.dispose();
//_formKey.currentState.dispose();
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
// key: globalKey,
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 52,
),
Row(
children: [
SizedBox(
width: 10,
),
Padding(
padding: const EdgeInsets.only(right: 90),
child: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(
Icons.arrow_back_ios,
color: Colors.white,
)),
),
Row(
children: [
Container(
color: Colors.white,
height: 3,
width: 28,
),
SizedBox(
width: 6,
),
Container(
color: Colors.grey,
height: 3,
width: 28,
),
SizedBox(
width: 6,
),
Container(
color: Colors.grey,
height: 3,
width: 28,
),
],
)
],
),
Text(
"STEP 1 OF 3",
style: TextStyle(
color: Color(0xffBCB6D1), fontSize: 10, letterSpacing: 0.63),
),
SizedBox(
height: 6,
),
Text(
"Your dog's profile",
style: GoogleFonts.montserrat(
textStyle: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.w700,
letterSpacing: -0.4)),
)
],
),
),
bottomSheet: YourBottomSheet(),
floatingActionButton: InkWell(
onTap: () {
print(_image);
getImage();
},
child: Container(
height: 126,
width: 126,
decoration: BoxDecoration(
image: fileSelected
? DecorationImage(image: FileImage(_image), fit: BoxFit.cover)
: null,
borderRadius: BorderRadius.circular(100),
color: Color(0xffEAE8F2),
),
child: fileSelected
? null
: Icon(
Icons.add_a_photo_outlined,
color: Colors.grey,
size: 50,
)),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
@override
bool get wantKeepAlive => true;
}
class YourBottomSheet extends StatefulWidget {
@override
_YourBottomSheetState createState() => _YourBottomSheetState();
}
class _YourBottomSheetState extends State<YourBottomSheet> {
TextEditingController petname = TextEditingController();
TextEditingController hisage = TextEditingController();
TextEditingController templevel = TextEditingController();
final _formKey = GlobalKey<FormState>();
bool pressAttention = false;
bool pressAttention2 = false;
var selectedtemperament = "";
_selectTemperament() {
List temperament = [
"Stable",
"Confident",
"Aggressive",
"Friendly",
"Protective"
];
return showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 400,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25), topRight: Radius.circular(25)),
color: Colors.white),
child: Column(
children: [
SizedBox(
height: 30,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Temperament Level",
textAlign: TextAlign.left,
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.w700),
),
IconButton(
icon: Icon(Icons.close),
onPressed: () => Navigator.pop(context),
),
],
),
),
ListView.builder(
shrinkWrap: true,
itemCount: temperament.length,
itemBuilder: (BuildContext context, int index) {
var temp = temperament[index];
return Column(
children: [
ListTile(
title: InkWell(
onTap: () {
print("$temp");
setState(() {
selectedtemperament = temp;
});
Navigator.pop(context);
},
child: Text(
'$temp',
style: TextStyle(fontWeight: FontWeight.w500),
)),
),
],
);
},
),
],
),
);
},
);
}
_tempFormBody() {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 70,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FlatButton(
minWidth: 126,
height: 36,
onPressed: () {
setState(() {
pressAttention = !pressAttention;
pressAttention2 = false;
});
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
FontAwesomeIcons.mars,
color: pressAttention
? Color(0xffFF4AAB)
: Color(0xff9891B4),
),
SizedBox(
width: 5,
),
Text(
"Male",
style: GoogleFonts.montserrat(
textStyle: TextStyle(
color: pressAttention
? Color(0xffFF4AAB)
: Color(0xff9891B4),
fontWeight: FontWeight.w600,
fontSize: 14)),
)
],
),
color: pressAttention ? Color(0xffFFECF6) : Colors.transparent,
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1,
color: pressAttention
? Color(0xffFF4AAB)
: Color(0xff9891B4)),
borderRadius: BorderRadius.circular(66.0),
),
),
SizedBox(
width: 15,
),
FlatButton(
minWidth: 126,
height: 36,
onPressed: () {
setState(() {
pressAttention2 = !pressAttention2;
pressAttention = false;
});
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
FontAwesomeIcons.venus,
color: pressAttention2
? Color(0xffFF4AAB)
: Color(0xff9891B4),
),
SizedBox(
width: 5,
),
Text(
"Female",
style: GoogleFonts.montserrat(
textStyle: TextStyle(
fontSize: 14,
color: pressAttention2
? Color(0xffFF4AAB)
: Color(0xff9891B4)),
fontWeight: FontWeight.w600),
)
],
),
color: pressAttention2 ? Color(0xffFFECF6) : Colors.transparent,
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1,
color: pressAttention2
? Color(0xffFF4AAB)
: Color(0xff9891B4)),
borderRadius: BorderRadius.circular(66.0),
),
),
],
),
SizedBox(
height: 5,
),
Container(
width: 305,
child: TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter pets name';
}
return null;
},
controller: petname,
decoration: InputDecoration(
labelText: "Pets Name",
hintStyle: TextStyle(color: Colors.grey),
focusColor: Colors.grey,
labelStyle: TextStyle(color: Color(0xffBCB6D1), fontSize: 14),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff1E163E))),
hintText: "eg:- bruno"),
),
),
SizedBox(
height: 20,
),
Container(
width: 305,
child: TextFormField(
validator: (value) {
int a = int.parse(value);
if (a < 1) {
return 'Number cant be zero';
} else if (value.isEmpty) {
return 'Enter age';
}
return null;
},
controller: hisage,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
], // Only nu
decoration: InputDecoration(
labelText: "His Age",
labelStyle: TextStyle(color: Color(0xffBCB6D1), fontSize: 14),
hintStyle: TextStyle(color: Colors.grey),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff1E163E))),
border: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xffBCB6D1))),
hintText: "His Age"),
),
),
SizedBox(
height: 20,
),
Container(
width: 305,
child: TextFormField(
onTap: () => _selectTemperament(),
focusNode: AlwaysDisabledFocusNode(),
initialValue: "$selectedtemperament",
style: TextStyle(fontSize: 16, color: Color(0xff4D466A)),
decoration: InputDecoration(
labelStyle: TextStyle(color: Color(0xffBCB6D1), fontSize: 14),
suffixIcon: IconButton(
icon: Icon(
FontAwesomeIcons.chevronDown,
color: Color(0xffBCB6D1),
size: 16,
),
onPressed: null,
),
labelText: "Temperament level",
hintStyle: TextStyle(color: Colors.grey),
border: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xffBCB6D1))),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff1E163E))),
)),
),
Expanded(child: Container()),
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: ElevatedButton(
child: Text("CONTINUE"),
onPressed: () {
if (_formKey.currentState.validate()) {
Navigator.pushNamed(context, '/selectbreed');
}
},
),
)
],
),
);
}
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: MediaQuery.of(context).size.height * 0.67,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25), topRight: Radius.circular(25)),
color: Colors.white),
child: Padding(
padding: const EdgeInsets.only(left: 2, right: 2),
child: _tempFormBody(),
),
);
}
}
class AlwaysDisabledFocusNode extends FocusNode {
@override
bool get hasFocus => false;
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: CreateProfile(),
);
}
}
推荐阅读
- xml - 防止 IIS 6.2 中的 XML 缓存
- diff - 如何在 Perforce/P4V 中使用 010 编辑器比较文件
- python - EC2 SSH 进入其他 SSH 并运行 bash 脚本
- google-chrome - 即使请求被缓存,Chrome 也会限制与域的同时连接
- php - laravel SQLSTATE [22007]:无效的日期时间格式:1366 不正确的十进制值:'buy_amt * 0.00097812555575316' 列 'price' 在第 1 行错误
- scala - 如何使用 spark scala 将数据帧转换为 RDD 并将其存储在 cassandra
- javascript - 在所有测试都以开玩笑的方式运行后,如何在 node.js 中关闭 pg-promise 连接?
- html - 如何按x轴拉伸表格单元格中的背景图像?
- python - 访问字典,用字典中的信息替换用户输入中的项目
- vba - 如何在一个模块中运行两个应用程序