So I'm currently creating this little web app that's basically like
You can change both, the title and the caption. But when you drag the window to a new position, the title and caption reset.
To create windows, I created different widgets, which all extend the Window class. The Window class looks like this:
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;
});
},
),
),
);
}
}
As you can see, a child needs to be passed which is gonna be displayed in the main container. I am not sure if I am doing the extending thing right (I'm quite a beginner) but here's the code for my 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;
}
}
I can't find the point where a state update might reset the child to its origin.
To have a look at the issue yourself: https://weazleboii.github.io/webboard/index.html#/
CodePudding user response:
I'm going to guess that you're seeing this because you don't actually put any state into your stateful widget. Whenever you drag the window, I guess it forces a repaint of all the widgets, and if your stateful widget kept the state of the text field, I imagine all would be well.
So for example, in _WindowState
you could have, in addition to what you have:
class _WindowState extends State<Window> {
String fieldValue = "";
@override
void initState() {
super.initState();
fieldValue = widget.title;
}
Now at this point, your stateful widget contains the fieldValue
, so now when you change it, update the state, and use it. For example:
...TextField(
...,
onChanged: (value) {
setState(() {
fieldValue = value;
});
}
)
Now if you used fieldValue
all should be okay....
I'd also move things like controller
into the _WindowState
class.
(This won't fix the textfield that you pass in as a child (I wonder why you do that), as it doesn't have any state saved anywhere either.)