在 Flutter 中,如何动画将容器从 0 高度扩展到其内容的高度?

问题描述

我有一个容器,它从零高度开始,需要在用户交互后展开。

  • 我尝试使用 AnimatedContainer / AnimatedSize 并将子小部件的高度从 0 更改为 null,但在这两种情况下,Flutter 都抱怨它无法从 0 插值到 {{1 }}。
  • 我也尝试过使用 BoxConstraints(使用 null 扩展)而不是明确的高度,在这种情况下,Flutter 抱怨它无法从有限值插入到无限值。
  • 我还尝试将 mainAxisSize 设置为 min/max,在这种情况下 Flutter 抱怨 maxHeight = double.infinityvsync

如何动画扩展一个小部件,使其动态增长到足够大以包裹其内容?如果这不能动态完成,那么有什么安全的方法来调整内容大小,使其在屏幕尺寸上有意义?在 Web 开发中,我知道 null 之类的东西是相对大小的,但在 Flutter 的上下文中,我不知道如何可靠地控制事物的大小。


更新:正如@pskink 所建议的那样,将子组件包装在 Align 小部件中并为 Align 的 heightFactor 参数设置动画即可完成折叠。但是,当倒塌的孩子本身有孩子时,我仍然无法倒塌。例如,Column 小部件根本不使用 ClipRect 进行裁剪(请参阅 https://github.com/flutter/flutter/issues/29357),即使我使用 Wrap 而不是 Column,如果 Wrap 的子项是 Row,那也不起作用。不确定如何让剪辑始终如一地工作。

解决方法

也许你也可以用 SizeTransition 解决这个问题?

enter image description here

class VariableSizeContainerExample extends StatefulWidget {
  VariableSizeContainerExample();

  @override
  _VariableSizeContainerExampleState createState() => _VariableSizeContainerExampleState();
}

class _VariableSizeContainerExampleState extends State<VariableSizeContainerExample> with TickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 1),vsync: this,);
    _animation = CurvedAnimation(
      parent: _controller,curve: Curves.fastLinearToSlowEaseIn,);
  }

  _toggleContainer() {
    print(_animation.status);
    if (_animation.status != AnimationStatus.completed) {
      _controller.forward();
    } else {
      _controller.animateBack(0,duration: Duration(seconds: 1));
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: Column(
            children: [
              TextButton(
                onPressed: () => _toggleContainer(),child: Text("Toggle container visibility"),),SizeTransition(
                sizeFactor: _animation,axis: Axis.vertical,child: Container(
                  child: Text(
                    "This can have variable size",style: TextStyle(fontSize: 40),Text("This is below the above container"),],);
  }
}
,

将@pskink 的评论移到后人的答案中:

主要概念是 Align 小部件有一个名为 heightFactor 的属性,它需要一个介于 0 和 1 之间的双精度来缩放其孩子的高度(也有类似的 widthFactor 属性用于宽度)。通过动画这个属性,我们可以折叠/展开孩子。例如:

ClipRect(
      child: Align(
        alignment: alignment,child: Align(
          alignment: innerAlignment,widthFactor: constantValue,heightFactor: animatedValue.value,child: builder(context,animation),)
)

其中 animatedValueAnimation<double> 类型,ClipReact 用于剪辑/截断子小部件。请注意,ClipReact 需要包裹在Align 小部件的外部;包装 Align 的子小部件时,它无法始终如一地工作。

编辑:动画的接收者也必须是 AnimatedWidget 才能使事情顺利进行。请参阅所选答案,了解为您处理此问题的方法。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...