Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
811 views
in Technique[技术] by (71.8m points)

flutter - SliverGrid doesn't get updated by setState if DragTarget and LongPressDraggable is used

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?

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Finally, I figured out that the issue was the missing implementation of the operator== and hashCode in my MainUnitContainer widget.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...