【问题标题】:Flutter AnimatedList still janky?Flutter AnimatedList 仍然卡顿?
【发布时间】:2020-06-19 22:31:49
【问题描述】:

我目前在我的 Flutter 应用程序中使用 AnimatedList,并且在删除列表项的动画方式方面存在问题。
动画本身按预期工作,但一旦删除的项目完成动画,它就会消失,导致其他小部件跳到它的位置。我曾预计其他项目会过渡到已删除项目的位置......

我尝试用ScaleTransition 包装我的列表项,但这没有帮助 - 其他列表项在完成动画之前仍然不会对删除的项做出反应。

这种方式违背了 AnimatedList 的目的吧?还是我做错了什么?关于 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));
      }

【问题讨论】:

    标签: animation flutter dart


    【解决方案1】:

    关键是触发两个Transitions一个SlideTranstion()和另一个SizeTransition来消除item被移除时的跳转

    这里是一些示例代码

    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() 包装在一个 heightFactor 为零的对齐小部件中,这样它就不会影响堆栈高度,并允许尺寸动画为盒子的高度
    • 你也可以将 SizeTransition() 包裹在 Opacity() 中,让它完全消失
    【解决方案2】:

    您需要使用应用的发布版本来测试性能。

    【讨论】:

      猜你喜欢
      • 2020-10-02
      • 2021-05-17
      • 2021-11-10
      • 1970-01-01
      • 2020-09-01
      • 2020-07-02
      • 1970-01-01
      • 1970-01-01
      • 2019-10-24
      相关资源
      最近更新 更多