Flutter动画列表还是卡顿吗?

4
我目前在我的Flutter应用中使用AnimatedList,但是我遇到了有关已删除的列表项退出动画方式的问题。虽然动画本身像预期的那样工作,但一旦已删除的项目完成动画,它就会消失,导致其他小部件跳入其位置。我原本希望其他项目过渡到已删除的项目的位置...
我尝试将列表项包装在ScaleTransition中,但这并没有帮助-其他列表项仍然不会对已删除的项目做出反应,直到它完成动画为止。
这有点违背AnimatedList的目的,对吗?还是我做错了什么? "Widget of the week"关于AnimatedList的视频清楚地显示,列表项通过更改其位置对新插入的项做出反应...
这是我的代码:
@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,
        ),
      ),
    );
  }
}

然后在MyCustomWidget的某个位置调用此函数:

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));
      }
2个回答

2
关键是触发两个转换,一个是SlideTranstion(),另一个是SizeTransition,以消除移除项目时的跳动。以下是一些示例代码。
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

我将两个动画放在一个堆栈中,并将SlideTransition()包装在一个高度因子为零的对齐小部件中,这样它就不会影响堆栈高度,并且允许大小动画来动画化方框的高度。 - Steve Mimshak
你也可以将SizeTransition()包裹在Opacity()中,使其完全消失。 - Steve Mimshak

-1
你需要使用应用程序的发布版本来测试性能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接