Flutter AnimatedList still janky?

岁酱吖の 提交于 2021-01-27 22:13:22

问题


I'm currently using an AnimatedList in my Flutter app and having problems with the way removed list items are animated out.
The animation itself works as expected but once the removed item finishes animating, it just disappears causing the other widgets to jump into its place. I had expected the other items to transition into the place of the removed item ...

I tried wrapping my list items with a ScaleTransition but that didn't help - the other list items still do not react to the removed item until it has finished the animation.

This kind of defies the purpose of AnimatedList, right? Or did I do something wrong? The "Widget of the week" video about AnimatedList clearly shows that list items react to newly inserted items by changing their position ...

Here is my code:

@override
Widget build(BuildContext context) {
  return AnimatedList(
    padding: EdgeInsets.only(top: REGULAR_DIM,
        bottom: REGULAR_DIM + kBottomNavigationBarHeight),
    initialItemCount: data.length,
    itemBuilder: (context, index, animation) {
      return MyCustomWidget(
          data: data[index],
          animation: animation,
          disabled: false
      );
    },
  );
}

class MyCustomWidget extends AnimatedWidget {
  final MyModel data;
  final bool disabled;

  MyCustomWidget({
    @required this.data,
    @required Animation<double> animation,
    this.disabled = false
  }) : super(listenable: animation);

  Animation<double> get animation => listenable;


  @override
  Widget build(BuildContext context) {
    final content = ... ;

    return ScaleTransition(
      scale: CurvedAnimation(
          parent: animation,
          curve: Interval(0, 0.25)
      ).drive(Tween(begin: 0, end: 1)),
      child: FadeTransition(
        opacity: animation,
        child: SlideTransition(
          position: animation.drive(
              Tween(begin: Offset(-1, 0), end: Offset(0, 0))
                  .chain(CurveTween(curve: Curves.easeOutCubic))),
          child: content,
        ),
      ),
    );
  }
}

And then somewhere in the MyCustomWidget I invoke this function:

void _remove(BuildContext context) async {
        final animatedList = AnimatedList.of(context);

        // obtain myModel asynchronously

        myModel.removeData(data);
        animatedList.removeItem(index, (context, animation) => MyCustomWidget(
          data: data,
          animation: animation,
          disabled: true,
        ), duration: Duration(milliseconds: 350));
      }

回答1:


The key is to trigger two Transitions one SlideTranstion() and another SizeTransition to eliminate to jump when the item is removed

here is some sample code

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(title: Text('Update AnimatedList data')),
        body: BodyWidget(),
      ),
    );
  }
}

class BodyWidget extends StatefulWidget {
  @override
  BodyWidgetState createState() {
    return new BodyWidgetState();
  }
}

class BodyWidgetState extends State<BodyWidget>
    with SingleTickerProviderStateMixin {
  // the GlobalKey is needed to animate the list
  final GlobalKey<AnimatedListState> _listKey = GlobalKey(); // backing data
  List<String> _data = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        SizedBox(
          height: 400,
          child: AnimatedList(
            key: _listKey,
            initialItemCount: _data.length,
            itemBuilder: (context, index, animation) {
              return _buildItem(
                _data[index],
                animation,
              );
            },
          ),
        ),
        RaisedButton(
          child: Text(
            'Insert single item',
            style: TextStyle(fontSize: 20),
          ),
          onPressed: () {
            _onButtonPress();
          },
        ),
        RaisedButton(
          child: Text(
            'Remove single item',
            style: TextStyle(fontSize: 20),
          ),
          onPressed: () {
            _removeSingleItems();
          },
        ),
      ],
    );
  }

  Widget _buildItem(String item, Animation<double> animation, {direction: 0}) {
    return (direction == 0)
        ? SizeTransition(
            sizeFactor: animation,
            child: Card(
              color: Colors.amber,
              child: ListTile(
                title: Text(
                  item,
                  style: TextStyle(fontSize: 20),
                ),
              ),
            ),
          )
        : Stack(
            children: [
              SizeTransition(
                sizeFactor: animation,
                child: Card(
                  color: Colors.transparent,
                  child: ListTile(
                    title: Text(
                      item,
                      style: TextStyle(fontSize: 20),
                    ),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.topCenter,
                heightFactor: 0,
                child: SlideTransition(
                  position: animation
                      .drive(Tween(begin: Offset(-1, 0), end: Offset(0, 0))),
                  child: Card(
                    color: Colors.red,
                    child: ListTile(
                      title: Text(
                        item,
                        style: TextStyle(fontSize: 20),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          );
  }

  void _onButtonPress() {
    _insertSingleItem();
  }

  void _insertSingleItem() {
    String item = "Pig";
    int insertIndex = 2;
    _data.insert(insertIndex, item);
    _listKey.currentState.insertItem(insertIndex);
  }

  void _removeSingleItems() {
    int removeIndex = 2;
    String removedItem = _data.removeAt(removeIndex);
    // This builder is just so that the animation has something
    // to work with before it disappears from view since the
    // original has already been deleted.
    AnimatedListRemovedItemBuilder builder = (context, animation) {
      // A method to build the Card widget.

      return _buildItem(removedItem, animation, direction: 1);
    };
    _listKey.currentState.removeItem(removeIndex, builder);
  }

  void _updateSingleItem() {
    final newValue = 'I like sheep';
    final index = 3;
    setState(() {
      _data[index] = newValue;
    });
  }
}
enter code here


来源:https://stackoverflow.com/questions/60576765/flutter-animatedlist-still-janky

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!