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更改了容器的宽度和高度,则会进行动画处理。但是,当将两个新的小部件列表添加到构建函数时,没有动画。
我想要一个扩展的动画。因为我正在使用扩展,所以我无法给出特定的高度,这对于扩展来说是没有意义的。
我该怎么做?
答案 0 :(得分:1)
这几乎可以肯定是重复的,因为我想我以前已经回答过这个问题,但是我很难找到问题,所以我将再次回答。
要了解为什么此方法不起作用,首先必须了解Dart如何对对象进行比较。如果对象是原始对象,简单对象或定义了比较函数/运算符(即int,boolean,String等),则dart可以比较对象。如果对象更复杂并且没有定义compareTo
,operator=
,operator<
或operator>
,则dart不知道如何对它进行这种类型的比较。取而代之的是,比较变成“对象b是否与对象b相同”。
这很重要,因为Flutter很懒。除非绝对必要,否则它不需要重新构建小部件。因此,当您使用setState更改状态时,随即出现抖动,并查看您的State以查看其是否实际更改。使用height
或width
的情况很简单-它可以检查情况是否已更改。
当您对列表进行变异时,它不起作用的原因正是这样;您要更改现有列表。因此,当dart检查oldState.widgetList
== newState.widgetList
时,实际上不是在比较列表的每个元素是否相同,而是在检查列表是否相同。由于是同一对象,因此列表显示为相同,因此flutter无需重建即可继续进行下一步。
有三种主要方法可以解决此问题。第一种是每次编辑列表时都要复制一份。根据列表中有多少个元素,这可能不是一个好主意-复制元素时,您实际上并没有复制每点信息,但仍然是O(n)操作。
第二个是在State中维护一个单独的变量。之所以有帮助,是因为如果状态的任何部分发生了变化,它都会触发所有小部件的重建,即调用build函数,而不管每个小部件使用的实际属性是否“已更改”(主要是因为难以管理每个构建的小部件的跟踪信息)。我个人就是这样做的-我维护一个整数计数器,每次列表中发生更改时,我都会递增该计数器。它可能不是最干净的解决方案,但它的性能很高而且非常简单!
最后一种方法是实现自己的列表,该列表会进行“深度”比较(即检查元素数量是否相同,然后可能检查每个元素是否相同)。在dart的列表中,默认情况下不会执行此操作,因为如果您开始比较字符串而未意识到列表中的每个元素都可以用作比较的一部分,则很容易导致性能问题。
答案 1 :(得分:-1)
使用AnimatedSize而不是AnimatedContainer。
要使AnimatedSize
工作,我们需要在SingleTickerProviderStateMixin
上使用名为_JoinScreenState
的混合,并在{之后将vsync属性设置为当前实例(this
)。 {1}}将寻找其子项的变化并进行相应的动画处理,
AnimatedSize