AnimatedSwitcher不会进行动画

12

我正在尝试在我的应用程序中制作一个新闻部分。在显示新闻的页面上,我希望能够单击页面上的任何位置并获取下一条新闻。到目前为止,没有问题,但我希望它具有良好的动画效果,因此我尝试实现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),
        ),
      ),
    );
  }
}

除了动画,其他都正常工作。

编辑:我尝试添加一个key来使它不同,但仍然没有动画效果。

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,
          ),
        ),
      ],
    );
  }
}

它是否至少会跳转到相关新闻页面,即使没有动画效果? - easeccy
是的,但没有动画。 - Marylène Beaudin
2个回答

15
由于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));

  ...
}

10
传递具有不同属性的相同类型小部件不会触发动画,因为它们对于框架来说是相同的小部件。这也在description中提到。
如果“新”子代与“旧”子代是相同的小部件类型和键,但具有不同的参数,则AnimatedSwitcher不会在它们之间进行转换,因为就框架而言,它们是相同的小部件,现有小部件可以使用新参数进行更新。要强制进行转换,请在您希望被视为唯一的每个子小部件上设置一个Key(通常是ValueKey,用于区分此子项与其他子项的小部件数据)。以下是检查是否要执行动画的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;
            });
          },
     ),
])

我尝试使用每次单击时更改的currentIndex,但仍然没有动画。(我已经在我的问题中发布了我的小部件和密钥) - Marylène Beaudin
可能会帮助其他人。我没有意识到 key 属性需要在 Text 小部件上。我把它放在了与子元素和持续时间相同的左侧,这导致动画无法正常工作。 - jaredbaszler

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