【问题标题】:AnimatedSwitcher does not animateAnimatedSwitcher 没有动画
【发布时间】:2020-01-01 19:40:43
【问题描述】:

我正在尝试在我的应用中创建新闻部分。在这个将显示新闻的页面中,我希望能够单击页面上的任何位置并获取列表中的下一个新闻。到目前为止没有问题,但我希望它有一个漂亮的动画,所以我尝试实现 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,
          ),
        ),
      ],
    );
  }
}

【问题讨论】:

  • 即使没有动画,是否至少会更改到相关新闻页面?
  • 是的,但没有动画。

标签: flutter dart flutter-animation


【解决方案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));

  ...
}

【讨论】:

    【解决方案2】:

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

    如果“新”子项与“旧”子项的小部件类型和键相同, 但是使用不同的参数,那么 AnimatedSwitcher 不会做 它们之间的过渡,因为就框架而言, 它们是相同的小部件,现有的小部件可以使用 新参数。要强制进行转换,请将 Key 设置为 on 您希望被视为唯一的每个子小部件(通常是 小部件数据上的 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&lt;T&gt; 就是为了这个。

    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 尝试了这个,每次点击都会改变,但仍然没有动画。 (我已经用钥匙在我的问题中发布了我的小部件)
    • 可以帮助他人的东西。我没有意识到 key 属性需要在 Text 小部件上。我把它和孩子放在同一个左边,持续时间导致动画不起作用。
    猜你喜欢
    • 2020-06-13
    • 2019-12-24
    • 2020-01-01
    • 2017-05-24
    • 2021-07-03
    • 1970-01-01
    • 2017-06-21
    • 2015-12-30
    • 2020-05-19
    相关资源
    最近更新 更多