动画容器:RenderFlex 在底部溢出了154像素

4

在设置不同的内容高度时,我调整动画容器大小时遇到了问题。

调整大小时会抛出异常:

════════ 渲染库捕获的异常 ════════

在布局期间抛出了以下断言:

一个RenderFlex在底部溢出154个像素。

Animated container overflow

以下是一个最小化的示例,可重现该问题(在我的真实应用程序中要复杂得多,但你有自己的观点):

bool expanded;

initState() {
  super.initState();
  expanded = false;
}

void _toggleMode() {
  setState(() {
    expanded = !expanded;
  });
}

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text("Test")),
    body: AnimatedContainer(
      height: expanded ? 230 : 70,
      duration: Duration(milliseconds: 800),
      child: Column(
        children: <Widget>[
          Expanded(
            child: PageView.builder(
              itemBuilder: (context, position) {
                return expanded
                    ? Column(
                        children: <Widget>[
                          Container(height: 40, color: Colors.blue),
                          Container(height: 40, color: Colors.blue[400]),
                          Container(height: 40, color: Colors.blue[300]),
                          Container(height: 40, color: Colors.blue[200]),
                          Container(height: 40, color: Colors.blue[100]),
                        ],
                      )
                    : Column(
                        children: <Widget>[
                          Container(height: 40, color: Colors.blue),
                        ],
                      );
              },
            ),
          ),
          InkWell(onTap: _toggleMode, child: expanded ? Icon(Icons.keyboard_arrow_up) : Icon(Icons.keyboard_arrow_down))
        ],
      ),
    ),
  );
}

在展开或不展开的情况下,内容都适配容器(没有溢出),问题只会在调整大小时出现。

当然,如果使用基本的容器而不进行动画处理,就不会出现问题。

我该如何处理这个问题?

1个回答

12

之所以出现这种情况是因为您在检查展开状态后立即返回容器,而此时容器尚未达到其最终大小。

一种解决方法是使用带有NeverScrollableScrollPhysics()的ListView替换较大的列。

编辑:您甚至不需要再检查展开状态了,就可以得到正确的动画效果。

 bool expanded;

  initState() {
    super.initState();
    expanded = false;
  }

  void _toggleMode() {
    setState(() {
      expanded = !expanded;
    });
  }

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Test")),
      body: AnimatedContainer(
        height: expanded ? 230 : 70,
        duration: Duration(milliseconds: 800),
        child: Column(
          children: <Widget>[
            Expanded(
              child: PageView.builder(
                itemBuilder: (context, position) {
                  return ListView(
                    physics: NeverScrollableScrollPhysics(),
                        children: <Widget>[
                    Column(
                      children: <Widget>[
                          Container(height: 40, color: Colors.blue),
                          Container(height: 40, color: Colors.blue[400]),
                          Container(height: 40, color: Colors.blue[300]),
                          Container(height: 40, color: Colors.blue[200]),
                          Container(height: 40, color: Colors.blue[100]),
                      ],
                    ),
                  ],
                      );
//                      : Column(
//                    children: <Widget>[
//                      Container(height: 40, color: Colors.blue),
//                    ],
//                  );
                },
              ),
            ),
            InkWell(onTap: _toggleMode, child: expanded ? Icon(Icons.keyboard_arrow_up) : Icon(Icons.keyboard_arrow_down))
          ],
        ),
      ),
    );
  }

输入图像描述


3
谢谢,好技巧!就像你说的这只是一个解决方法,但它完成了工作。实际上我不仅有两个状态(展开或未展开),而是有多个高度不同的内容,所以我不得不把我的切换/情况提取出来成为一个函数,然后按照你的建议用不可滚动的可滚动小部件进行包装 :D 我使用了 SingleChildScrollView 而不是 ListView,我想这可能会更节约资源(?)。非常好用。 - Yann39
我想补充一点,只要在AnimatedContainer下放置任何小部件,并添加SingleChildScrollView即可解决问题。 - Aia's Blog

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