AnimatedSwitcher 没有动画

AnimatedSwitcher does not animate

我正在尝试在我的应用程序中创建一个新闻版块。在这个要显示新闻的页面中,我希望能够单击页面上的任意位置并获取列表中的下一个新闻。到目前为止没问题,但我希望它有一个漂亮的动画,所以我尝试实现 AnimatedSwitcher,但我不明白为什么没有动画显示。

我尝试更改代码的层次结构。将手势检测器放在动画切换器内,反之亦然。也让主容器在外面或里面。我尝试了一个动画生成器,它可以缩放它以防万一它不够明显但什么也没有。也尝试过更改持续时间,但事实并非如此。

class ShowNews extends StatefulWidget {
  @override
  _ShowNewsState createState() => _ShowNewsState();
}

class _ShowNewsState extends State<ShowNews> {
  List<News> _news = [
    News(title: 'OYÉ OYÉ', desc: 'bla bla bla bla bla'),
    News(title: 'another one', desc: 'plus de bout d\'histoire'),
    News(title: 'boum', desc: 'attention à l\'accident'),
    News(title: 'Lorem ipsum', desc: 'Lorem ipsum in doloris'),
  ];

  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {
          if (_currentIndex < _news.length - 1) {
            _currentIndex++;
          } else {
            _currentIndex = 0;
          }
        });
      },
      child: Container(
        height: 160,
        padding: EdgeInsets.all(20.0),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(20.0),
            topRight: Radius.circular(20.0),
          ),
        ),
        child: AnimatedSwitcher(
          duration: Duration(seconds: 5),
          child: ColumnArticle(_news, _currentIndex),
        ),
      ),
    );
  }
}

除动画外一切正常。

编辑:我尝试添加一个键使其不同但仍然没有动画。

class ColumnArticle extends StatelessWidget {
  final List<News> _news;
  final int _currentIndex;

  ColumnArticle(this._news, this._currentIndex);

  @override
  Widget build(BuildContext context) {
    return Column(
      key: ValueKey<int>(_currentIndex),
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[
        Text(
          _news[_currentIndex].title,
          textAlign: TextAlign.left,
          style: TextStyle(
            fontSize: 20.0,
          ),
        ),
        SizedBox(
          height: 10.0,
        ),
        Text(
          _news[_currentIndex].desc,
          style: TextStyle(
            fontSize: 14.0,
          ),
        ),
      ],
    );
  }
}

传递具有不同属性的相同类型的小部件将不会触发动画,因为它们是框架的相同小部件。 description.

中也提到了它

If the "new" child is the same widget type and key as the "old" child, but with different parameters, then AnimatedSwitcher will not do a transition between them, since as far as the framework is concerned, they are the same widget and the existing widget can be updated with the new parameters. To force the transition to occur, set a Key on each child widget that you wish to be considered unique (typically a ValueKey on the widget data that distinguishes this child from the others).

这是来自 AnimatedSwitcher 的代码,用于检查是否设置动画:

if (hasNewChild != hasOldChild ||
      hasNewChild && !Widget.canUpdate(widget.child, _currentEntry.widgetChild)) {
    // Child has changed, fade current entry out and add new entry.
    _childNumber += 1;
    _addEntryForNewChild(animate: true);
}

这是框架中的静态 canUpdate 方法:

static bool canUpdate(Widget oldWidget, Widget newWidget) {
  return oldWidget.runtimeType == newWidget.runtimeType
      && oldWidget.key == newWidget.key;
}

要解决此问题,您可以根据不同的属性(例如文本、计数、值)为 News 小部件设置单独的键。 ValueKey<T> 就是为了这个。

Column(
  children: <Widget>[
     AnimatedSwitcher(
         duration: const Duration(milliseconds: 500),
    
         child: Text(
             '$_count',
             // This key causes the AnimatedSwitcher to interpret this as a "new"
             // child each time the count changes, so that it will begin its animation
             // when the count changes.
             key: ValueKey<int>(_count),
         ),
     ),
     RaisedButton(
          child: const Text('Increment'),
          onPressed: () {
            setState(() {
              _count += 1;
            });
          },
     ),
])

发生这种情况是因为 AnimatedSwitcher 将随时添加动画 它是用不同的子引用重建的。但是,在您的小部件生命周期中,您始终将 ColumnArticle 作为子部件使用,因此,实际上并没有交换任何小部件类型,这就是 ValueKey 发挥作用的地方。

您可以使用索引作为键的参考,但确保它确实发生了变化,否则它不会起作用,您还需要将它传递给您的ColumnArticle 基本部件 (super).

因此,您的 ColumnArticle 应该如下所示:

class ColumnArticle extends StatelessWidget {
  final List<News> _news;
  final int _currentIndex;

  ColumnArticle(this._news, this._currentIndex) : super(key: ValueKey<int>(_currentIndex));

  ...
}