【问题标题】:Animated Container is not animating when list changed列表更改时动画容器没有动画
【发布时间】:2019-02-08 07:33:35
【问题描述】:
import "package:flutter/material.dart";
import "dart:async";

class JoinScreen extends StatefulWidget {
   @override
  _JoinScreenState createState() {   
   return _JoinScreenState();
          }
   }

class _JoinScreenState extends State<JoinScreen> {
  List<Widget> widgetList = [];

  @override
  void initState() {
    new Timer(const Duration(milliseconds: 100), () {
     print('timeout');
    setState(() {        
       widgetList.add(secondHalf());
     });
    });

new Timer(const Duration(milliseconds: 1000), () {
  print('timeout');
  setState(() {        
    widgetList.add(firstHalf());
  });
});

super.initState();
 }

 @override
 Widget build(BuildContext context) {
   return AnimatedContainer(
     duration: Duration(seconds: 2),
      child: Column(
       children: widgetList,
     ),
   );
 }

 Widget firstHalf() {
   return Expanded(
     child: Container(
       decoration: BoxDecoration(color: Colors.blueAccent),
     ),
   );
 }

 Widget secondHalf() {
   return Expanded(
     child: Container(
       decoration: BoxDecoration(color: Colors.pinkAccent),
     ),
     );
    }
}

如果我在计时器和 setstate 的帮助下更改了容器的宽度和高度,它会生成动画。但是当向构建函数添加两个新的小部件列表时,没有任何动画。

我想要一个展开的动画。因为我使用的是展开式,所以我无法给出展开后没有意义的特定高度。

我该怎么做?

【问题讨论】:

    标签: flutter flutter-animation


    【解决方案1】:

    使用 AnimatedSize 代替 AnimatedContainer。

    为了使AnimatedSize 工作,我们需要在_JoinScreenState 上使用名为SingleTickerProviderStateMixin 的mixin,并将vsync 属性设置为当前实例(this),然后AnimatedSize 将在其上查找更改孩子和相应的动画,

    这是你的代码

    import "package:flutter/material.dart";
    import "dart:async";
    
    class JoinScreen extends StatefulWidget {
    @override
     _JoinScreenState createState() {   
        return _JoinScreenState();
        }
     }
    
    class _JoinScreenState extends State<JoinScreen> 
     with SingleTickerProviderStateMixin {
      List<Widget> widgetList = [];
    
      @override
      void initState() {
        new Timer(const Duration(milliseconds: 100), () {
        print('timeout');
        setState(() {        
        widgetList.add(secondHalf());
       });
      });
    
      new Timer(const Duration(milliseconds: 1000), () {
        print('timeout');
        setState(() {        
          widgetList.add(firstHalf());
        });
      });
    
      super.initState();
     }
    
     @override
     Widget build(BuildContext context) {
       return AnimatedSize(
         vsync: this,
         duration: Duration(seconds: 2),
         child: Column(
           children: widgetList,
           ),
       );
     }
    
     Widget firstHalf() {
       return Expanded(
         child: Container(
           decoration: BoxDecoration(color: Colors.blueAccent),
         ),
       );
     }
    
     Widget secondHalf() {
       return Expanded(
         child: Container(
           decoration: BoxDecoration(color: Colors.pinkAccent),
         ),
        );
      }
    }
    

    【讨论】:

    • 欢迎来到 Stack Overflow。您能否对您的建议更具体一点,也许显示一个代码 sn-p? take the tour 也是个好主意,阅读 How to Ask
    • 抱歉没有具体说明。 @AnnKilzer 修复了它。
    【解决方案2】:

    这几乎可以肯定是重复的,因为我想我以前已经回答过这个问题,但我不能轻易找到问题,所以我会再回答一次。

    要了解为什么这不起作用,首先您必须了解 Dart 如何对对象进行比较。如果一个对象是原始的、简单的或定义了比较函数/运算符(即 int、boolean、String 等),dart 可以比较对象。如果一个对象更复杂并且没有定义compareTooperator=operator&lt;operator&gt;,dart 不知道如何对其进行这种类型的比较。相反,比较变成“对象 a 是否与对象 b 相同”。

    这很重要,因为 Flutter 很懒惰。它不想重建小部件,除非它绝对必须这样做。因此,当您使用 setState 更改状态时,flutter 会出现并查看您的 State 以查看它是否真的发生了变化。对于 heightwidth 的情况,这很容易 - 它可以检查这些情况是否发生了变化。

    当你改变你的列表时它不起作用的原因就是这样;你正在改变一个现有的列表。所以当dart检查是否oldState.widgetList == newState.widgetList时,实际上并不是比较列表的每个元素是否相同,而是检查列表是否相同。由于它是同一个对象,因此列表显示为相同,因此 Flutter 无需重建即可继续下一步。

    有三种主要方法可以解决这个问题。第一个是在每次编辑列表时制作一份副本。根据列表中有多少元素,这可能是个坏主意 - 当您复制元素时,您实际上并没有复制每一点信息,但它仍然是一个 O(n) 操作。

    第二个是在State中维护一个单独的变量。这有帮助的原因是,如果状态的任何部分发生了变化,它会触发所有小部件的重建,即调用构建函数,无论每个小部件使用的实际属性是否“改变”(主要是因为它会非常很难管理跟踪每个构建的小部件)。我个人是这样做的——我维护一个整数计数器,每次列表中发生更改时我都会递增该计数器。它可能不是最干净的解决方案,但它非常高效且非常简单!

    最后一种方法是实现您自己的列表,它会进行“深度”比较(即检查元素的数量是否相同,然后可能检查每个元素是否相同)。在 dart 的列表中默认情况下不会这样做,因为如果您开始比较字符串而没有意识到列表中的每个元素都可以用作比较的一部分,那么很容易导致性能问题。

    【讨论】:

    • 谢谢,有机会我会编辑的。我想我的意思是写 operator ==。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-02
    • 2017-05-24
    • 2021-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多