I'm trying to create a SliverGrid with Draggable items.
The grid gets updated if I put the SliverPadding into the CustomScrollView's slivers: list but the grid (UI) does not get updated when it is in a separate widget regardless of calling the setState.
This is my Scaffold:
Scaffold(
key: _scaffoldKey,
drawer: Menu(),
body: DraggableGrid(
padding: EdgeInsets.all(10),
children: mainUnits,
placeholder: MainUnitContainer(child: null),
sliverAppBar: SliverAppBar(
floating: true,
title: Text('Title'),
backgroundColor: Colors.blueAccent,
expandedHeight: 150.0,
flexibleSpace: FlexibleSpaceBar(
background: Placeholder(),
))))
This is my DraggableGrid:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class DraggableGrid<@required T> extends StatefulWidget {
DraggableGrid({@required this.children, @required this.placeholder, @required this.padding, this.sliverAppBar});
final List<T> children;
final T placeholder;
final SliverAppBar sliverAppBar;
final EdgeInsets padding;
@override
DraggableGridState createState() => DraggableGridState<T>(children, placeholder, padding, sliverAppBar);
}
class DraggableGridState<@required T> extends State<DraggableGrid> {
DraggableGridState(this.children, this.placeholder, this.padding, this.sliverAppBar);
List<T> children;
T placeholder;
T _widgetOnMove;
SliverAppBar sliverAppBar;
EdgeInsets padding;
@override
Widget build(BuildContext context) {
return CustomScrollView(slivers: <Widget>[
sliverAppBar,
SliverPadding(
padding: padding,
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return DragTarget(builder: (context, List<T> candidateData, movedData) {
if (movedData.length != 0) {
_widgetOnMove = movedData[0][0];
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
children.remove(_widgetOnMove);
if (children.indexOf(placeholder) != index) {
children.remove(placeholder);
}
if (children.indexOf(placeholder) == -1) {
children.insert(index, placeholder);
}
});
});
}
return LongPressDraggable(
child: children.elementAt(index) as Widget,
feedback: children.elementAt(index) as Widget,
data: [children[index]],
onDraggableCanceled: (velocity, offset) {
setState(() {
int position = children.indexOf(placeholder);
children.removeAt(position);
children.insert(position, _widgetOnMove);
});
},
maxSimultaneousDrags: 1,
);
}, onAccept: (Draggable<T> data) {
return true;
});
},
childCount: children.length,
)))
]);
}
}
I can clearly see that the mainUnits list is updated properly and the SliverChildBuilderDelegate's builder is called and the builder is using the updated mainUnits list. The UI though remains unchanged. Again, if I don't use the widget architecture but simply copying the SliverPadding into the CustomScrollView's slivers: list then it works fine (of course, mainUnits and _currentItem declarations should be copied together).
I'm trying to do this because using setState scrolls back to the top of the grid when the SliverPadding is placed into the CustomScrollView's slivers: list directly.
Any idea what am I doing wrong?