阻止 TextField 重置 after/while 拖动它的 parent
Stop a TextField from resetting after/while dragging its parent
所以我目前正在创建这个基本上类似于 https://classroomscreen.com/app 的小型 Web 应用程序。
它基于不同类型的 Windows,它们各有特点。 (文本 Window、媒体 Window、清单 Window 等)。
最近我完成了文本 Window,它看起来像这样:
您可以同时更改标题和说明。但是,当您将 window 拖动到新位置时,标题和说明会重置。
为了创建 windows,我创建了不同的小部件,它们都扩展了 Window class。 Window class 看起来像这样:
class Window extends StatefulWidget {
SystemMouseCursor cursor = SystemMouseCursors.grab;
String title = "";
final Widget child;
double x = Random().nextDouble() * 500;
double y = Random().nextDouble() * 500;
TextEditingController controller = TextEditingController();
Window({
Key? key,
required this.title,
required this.child,
}) : super(key: UniqueKey());
@override
State<Window> createState() => _WindowState();
}
class _WindowState extends State<Window> {
bool started = false;
@override
Widget build(BuildContext context) {
if (!started) {
setState(() {
widget.controller.text = widget.title;
});
}
return Positioned(
left: widget.x,
top: widget.y,
child: GestureDetector(
child: Draggable<Widget>(
child: Container(
width: 406.0,
height: 406.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
color: const Color.fromARGB(255, 249, 249, 249),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 12.0,
spreadRadius: 6.0,
offset: const Offset(4.0, 4.0),
),
BoxShadow(
color: Colors.white70.withOpacity(0.05),
blurRadius: 12.0,
spreadRadius: 6.0,
offset: const Offset(-4, -4),
)
]),
child: Stack(
children: [
const Positioned(
right: 0,
bottom: 0,
child: MouseRegion(
cursor: SystemMouseCursors.resizeDownRight,
child: SizedBox(
height: 15,
width: 15,
),
),
),
Positioned(
top: 84,
left: 24,
right: 24,
bottom: 24,
child: Container(
child: widget.child,
),
),
Positioned(
top: 0,
right: 0,
left: 0,
child: Container(
width: 406.0,
height: 60.0,
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(15.0),
),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
offset: const Offset(0, 6.0),
blurRadius: 12.0,
),
],
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Align(
alignment: Alignment.centerLeft,
child: SizedBox(
width: 358.0,
child: TextField(
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "",
),
controller: widget.controller,
style: GoogleFonts.montserrat(
fontSize: 20.0,
fontWeight: FontWeight.w600,
),
),
),
),
),
),
)
],
),
),
feedback: Material(
type: MaterialType.transparency,
child: Container(
width: 406.0,
height: 406.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
color: const Color.fromARGB(255, 249, 249, 249),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.015),
blurRadius: 12.0,
spreadRadius: 6.0,
offset: const Offset(0.0, 0.0),
),
]),
child: Stack(
children: [
Positioned(
top: 84,
left: 24,
right: 24,
bottom: 24,
child: Container(
child: widget.child,
),
),
Positioned(
top: 0,
right: 0,
left: 0,
child: Container(
width: 406.0,
height: 60.0,
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(15.0),
),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
offset: const Offset(0, 6.0),
blurRadius: 12.0,
)
]),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Align(
alignment: Alignment.centerLeft,
child: SizedBox(
width: 358.0,
child: TextField(
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "",
),
controller: widget.controller,
style: GoogleFonts.montserrat(
fontSize: 20.0,
fontWeight: FontWeight.w600,
),
),
),
),
),
),
)
],
),
),
),
childWhenDragging: Container(
height: 500,
width: 500,
color: Colors.transparent,
),
onDragEnd: (details) {
//set the item to position 0 in the list
setState(() {
widget.x = details.offset.dx;
widget.y = details.offset.dy;
});
},
),
),
);
}
}
如您所见,需要传递一个 child,它将显示在主容器中。
我不确定我是否正在做正确的扩展事情(我是一个初学者)但这是我的 TextWindow:
的代码
class TextWindow extends Window {
TextWindow({Key? key})
: super(
key: UniqueKey(),
title: "Text",
child: TextField(
onChanged: (value) {},
keyboardType: TextInputType.multiline,
maxLines: 50,
decoration: InputDecoration(
hintText: getRandomHint(),
border: InputBorder.none,
hintStyle: GoogleFonts.montserrat(
fontSize: 15.0,
fontWeight: FontWeight.w500,
),
),
style: GoogleFonts.montserrat(
fontSize: 15.0,
fontWeight: FontWeight.w600,
),
),
);
Widget build(BuildContext context) {
return this;
}
}
我找不到状态更新可能会将 child 重置为原点的点。
我猜你看到这个是因为你实际上并没有将任何状态放入你的有状态小部件中。每当您拖动 window 时,我猜它会强制重新绘制所有小部件,如果您的有状态小部件保持文本字段的状态,我想一切都会好起来的。
因此,例如,在 _WindowState
中,除了您拥有的之外,您还可以拥有:
class _WindowState extends State<Window> {
String fieldValue = "";
@override
void initState() {
super.initState();
fieldValue = widget.title;
}
此时,您的有状态小部件包含 fieldValue
,所以现在当您更改它时,更新状态并使用它。例如:
...TextField(
...,
onChanged: (value) {
setState(() {
fieldValue = value;
});
}
)
现在如果你使用 fieldValue
一切都应该没问题....
我还会将 controller
之类的内容移到 _WindowState
class 中。
(这不会修复您小时候传入的文本字段(我想知道您为什么这样做),因为它也没有在任何地方保存任何状态。)
所以我目前正在创建这个基本上类似于 https://classroomscreen.com/app 的小型 Web 应用程序。 它基于不同类型的 Windows,它们各有特点。 (文本 Window、媒体 Window、清单 Window 等)。 最近我完成了文本 Window,它看起来像这样:
您可以同时更改标题和说明。但是,当您将 window 拖动到新位置时,标题和说明会重置。
为了创建 windows,我创建了不同的小部件,它们都扩展了 Window class。 Window class 看起来像这样:
class Window extends StatefulWidget {
SystemMouseCursor cursor = SystemMouseCursors.grab;
String title = "";
final Widget child;
double x = Random().nextDouble() * 500;
double y = Random().nextDouble() * 500;
TextEditingController controller = TextEditingController();
Window({
Key? key,
required this.title,
required this.child,
}) : super(key: UniqueKey());
@override
State<Window> createState() => _WindowState();
}
class _WindowState extends State<Window> {
bool started = false;
@override
Widget build(BuildContext context) {
if (!started) {
setState(() {
widget.controller.text = widget.title;
});
}
return Positioned(
left: widget.x,
top: widget.y,
child: GestureDetector(
child: Draggable<Widget>(
child: Container(
width: 406.0,
height: 406.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
color: const Color.fromARGB(255, 249, 249, 249),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 12.0,
spreadRadius: 6.0,
offset: const Offset(4.0, 4.0),
),
BoxShadow(
color: Colors.white70.withOpacity(0.05),
blurRadius: 12.0,
spreadRadius: 6.0,
offset: const Offset(-4, -4),
)
]),
child: Stack(
children: [
const Positioned(
right: 0,
bottom: 0,
child: MouseRegion(
cursor: SystemMouseCursors.resizeDownRight,
child: SizedBox(
height: 15,
width: 15,
),
),
),
Positioned(
top: 84,
left: 24,
right: 24,
bottom: 24,
child: Container(
child: widget.child,
),
),
Positioned(
top: 0,
right: 0,
left: 0,
child: Container(
width: 406.0,
height: 60.0,
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(15.0),
),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
offset: const Offset(0, 6.0),
blurRadius: 12.0,
),
],
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Align(
alignment: Alignment.centerLeft,
child: SizedBox(
width: 358.0,
child: TextField(
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "",
),
controller: widget.controller,
style: GoogleFonts.montserrat(
fontSize: 20.0,
fontWeight: FontWeight.w600,
),
),
),
),
),
),
)
],
),
),
feedback: Material(
type: MaterialType.transparency,
child: Container(
width: 406.0,
height: 406.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
color: const Color.fromARGB(255, 249, 249, 249),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.015),
blurRadius: 12.0,
spreadRadius: 6.0,
offset: const Offset(0.0, 0.0),
),
]),
child: Stack(
children: [
Positioned(
top: 84,
left: 24,
right: 24,
bottom: 24,
child: Container(
child: widget.child,
),
),
Positioned(
top: 0,
right: 0,
left: 0,
child: Container(
width: 406.0,
height: 60.0,
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(15.0),
),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
offset: const Offset(0, 6.0),
blurRadius: 12.0,
)
]),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Align(
alignment: Alignment.centerLeft,
child: SizedBox(
width: 358.0,
child: TextField(
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "",
),
controller: widget.controller,
style: GoogleFonts.montserrat(
fontSize: 20.0,
fontWeight: FontWeight.w600,
),
),
),
),
),
),
)
],
),
),
),
childWhenDragging: Container(
height: 500,
width: 500,
color: Colors.transparent,
),
onDragEnd: (details) {
//set the item to position 0 in the list
setState(() {
widget.x = details.offset.dx;
widget.y = details.offset.dy;
});
},
),
),
);
}
}
如您所见,需要传递一个 child,它将显示在主容器中。 我不确定我是否正在做正确的扩展事情(我是一个初学者)但这是我的 TextWindow:
的代码class TextWindow extends Window {
TextWindow({Key? key})
: super(
key: UniqueKey(),
title: "Text",
child: TextField(
onChanged: (value) {},
keyboardType: TextInputType.multiline,
maxLines: 50,
decoration: InputDecoration(
hintText: getRandomHint(),
border: InputBorder.none,
hintStyle: GoogleFonts.montserrat(
fontSize: 15.0,
fontWeight: FontWeight.w500,
),
),
style: GoogleFonts.montserrat(
fontSize: 15.0,
fontWeight: FontWeight.w600,
),
),
);
Widget build(BuildContext context) {
return this;
}
}
我找不到状态更新可能会将 child 重置为原点的点。
我猜你看到这个是因为你实际上并没有将任何状态放入你的有状态小部件中。每当您拖动 window 时,我猜它会强制重新绘制所有小部件,如果您的有状态小部件保持文本字段的状态,我想一切都会好起来的。
因此,例如,在 _WindowState
中,除了您拥有的之外,您还可以拥有:
class _WindowState extends State<Window> {
String fieldValue = "";
@override
void initState() {
super.initState();
fieldValue = widget.title;
}
此时,您的有状态小部件包含 fieldValue
,所以现在当您更改它时,更新状态并使用它。例如:
...TextField(
...,
onChanged: (value) {
setState(() {
fieldValue = value;
});
}
)
现在如果你使用 fieldValue
一切都应该没问题....
我还会将 controller
之类的内容移到 _WindowState
class 中。
(这不会修复您小时候传入的文本字段(我想知道您为什么这样做),因为它也没有在任何地方保存任何状态。)