Drag to reorder + swipe to dismiss, dialog = broken animation?

527 views
Skip to first unread message

Michelle Ran

unread,
Aug 2, 2018, 5:12:37 PM8/2/18
to Flutter Dev
I'm building a ListView with items which you can drag to reorder, as well as swipe to dismiss. There's also a button in the app bar that shows a dialog. For dragging to reorder, I'm using this package, with some slight modifications to drag_and_drop_list.dart:

// same; omitted

class DragAndDropList<T> extends StatefulWidget {
  
  // same; omitted

  bool listWasChanged; // added

  DragAndDropList(this.rowsData,
      {Key key, @required this.itemBuilder,
        this.onDragFinish,
        @required this.canBeDraggedTo,
        this.dragElevation = 0.0,
        this.tilt = 0.0,
        this.listWasChanged = false}) // added
      : providesOwnDraggable = false,
        itemBuilderCustom = null, super(key: key);

  // same; omitted

}

class _DragAndDropListState<T> extends State<DragAndDropList> {

  // same; omitted

  @override
  Widget build(BuildContext context) {
    return new LayoutBuilder(
      builder: (BuildContext context3, constr) {

        if (widget.listWasChanged) // added
          rows = (widget.rowsData).map((it) => new Data<T>(it)).toList(); // added

        return new ListView.builder(
          itemBuilder: (BuildContext context2, int index) {
            return _getDraggableListItem(context2, index, context3);
          },
          controller: scrollController,
          itemCount: rows.length,
          padding: const EdgeInsets.all(0.0),
        );
      },
    );
  }

  // same; omitted

}

Here's my main.dart file:

import 'package:flutter/material.dart';
import 'package:flutter_list_drag_and_drop/drag_and_drop_list.dart';

void main() => runApp(new ExperimentApp());

class ExperimentApp extends StatelessWidget {

  ExperimentApp({Key key});

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Experimenting!',
      theme: new ThemeData(
        primaryColor: Colors.white,
        accentColor: Colors.deepOrange,
      ),
      home: new ListExperiment(
        title: 'Experiment Home Page',
        key: key,
      ),
    );
  }

}

class ListExperiment extends StatefulWidget {

  ListExperiment({Key key, this.title}) : super(key: key);
  final String title;

  @override
  ListExperimentState createState() => new ListExperimentState();
}

class ListExperimentState extends State<ListExperiment> {

  final List<String> _items = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']; // TODO: change to a Set
  final TextStyle _rankStyle = const TextStyle(fontSize: 20.0, color: Colors.deepOrange);

  bool listWasChanged = false;

  @override
  Widget build(BuildContext context) {
    Scaffold scaffold =  new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
        actions: <Widget>[
          new IconButton(icon: const Icon(Icons.add), onPressed: _addItem),
        ],
      ),
      body: new DragAndDropList<String>(
        _items,
        itemBuilder: (BuildContext context, item) => _buildRow(item),
        onDragFinish: (before, after) {
          String data = _items[before];
          _items.removeAt(before);
          _items.insert(after, data);
        },
        canBeDraggedTo: (one, two) => true,
        dragElevation: 8.0,
        listWasChanged: listWasChanged,
      ),
    );

    listWasChanged = false;

    return scaffold;
  }

  Widget _buildRow(String item) => new Dismissible(
      // Each Dismissible must contain a unique Key.
      key: new Key(item),
      onDismissed: (direction) {
        setState(() {
          _items.remove(item);
          listWasChanged = true;
        });
      },
      // Show a red background as the item is swiped away
      background: new Container(color: Colors.red),
      child: new SizedBox(
        child: new Card(
          child: new ListTile(
            leading: new Text(
              (_items.indexOf(item) + 1).toString(),
              style: _rankStyle,
            ),
            title: new Text(item),
          ),
        ),
      ),
  );

  void _addItem() {
    print("Going to make a new item...");
    setState(() {
      _showAddDialog(context);
      //_items.add('Item X');
      listWasChanged = true;
    });
  }

  void _showAddDialog(BuildContext context) {
    showDialog(
        context: context,
        barrierDismissible: false,
        builder: (BuildContext context) => new AlertDialog(
          title: new Center(child: new Text('Alert')),
          content: new Row(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children : <Widget>[
              new Expanded(
                child: new Text(
                  'Message here',
                  textAlign: TextAlign.center,
                ),
              )
            ],
          ),
          actions: <Widget>[
            new FlatButton(
                child: new Text('Cancel'),
                onPressed: () {
                  Navigator.of(context).pop();
                }),
            new FlatButton(
                child: new Text('Ok'),
                onPressed: () {
                  print('TODO: stuff');
                  Navigator.of(context).pop();
                })
          ],
        ),
    );
  }
}

Everything works so far, but after dismissing an item or showing the dialog, the animation for dragging to reorder partially breaks (see attached short video).

Calling widget.createState rather than setState after dismissing an item fixes the animation...but causes a host of other issues.

Any thoughts?
dragging.mov

Michelle Ran

unread,
Aug 4, 2018, 4:40:46 PM8/4/18
to Flutter Dev
Fixed - see issue #15.
Reply all
Reply to author
Forward
0 new messages