Flutter - 如何在 SimpleDialog 框中显示 GridView?

Posted

技术标签:

【中文标题】Flutter - 如何在 SimpleDialog 框中显示 GridView?【英文标题】:Flutter - How to display a GridView within an SimpleDialog box? 【发布时间】:2018-09-01 07:39:55 【问题描述】:

昨天问了一个非常相似的问题,关于在 AlertDialog 中显示 GridView 并得到了将 Widget 包装在容器中并添加宽度的完美答案。现在我决定 SimpleDialog 会更好,以提供更多功能/自定义,即搜索文本字段和多操作按钮。显示文本字段和图标按钮时,我得到了所需的结果,但是当我尝试添加 GridView 时,它会出错。我应用了以前的规则,但在 UI 消失但没有小部件显示的情况下,我遇到了类似的错误。我试过为不同的小部件添加宽度,但没有成功。这是我的代码...

Future<Null> _neverSatisfied() async 
    return showDialog<Null>(
      context: context,
      barrierDismissible: false, // user must tap button!
      child: new SimpleDialog(
        contentPadding: const EdgeInsets.all(10.0),
        title: new Text(
          'CHOOSE YOUR GIF PROFILE IMAGE',
          style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.blue),
          textAlign: TextAlign.center,
        ),
        children: <Widget>[
          new Column(
            mainAxisSize: MainAxisSize.max,
            children: <Widget>[
              new Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    new Padding(padding: new EdgeInsets.all(10.0)),
                    new Expanded(
                        child: new TextField(
                            decoration:
                                new InputDecoration(labelText: "SEARCH GIF'S"),
                            controller: _searchController,
                            onSubmitted: (str) 
                              setState(() 
                                str = _searchController.text;
                              );
                            )),
                    new Padding(padding: new EdgeInsets.all(2.0)),
                    new IconButton(
                      icon: new Icon(
                        Icons.search,
                        color: Colors.blue,
                      ),
                      onPressed: () 
                        print('$_searchController.text');
                      ,
                      highlightColor: Colors.amber,
                      splashColor: Colors.amber,
                      iconSize: 25.0,
                    ),
                  ]),
              new Padding(padding: new EdgeInsets.all(2.0)),

              new Container(
                // Specify some width
                width: MediaQuery.of(context).size.width * .5,
                child: new InkWell(
                  splashColor: Colors.blue,
                  onTap: null,
                  child: new GridView.count(
                      crossAxisCount: 4,
                      childAspectRatio: 1.0,
                      padding: const EdgeInsets.all(4.0),
                      mainAxisSpacing: 4.0,
                      crossAxisSpacing: 4.0,
                      children: <String>[
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                        'http://www.for-example.org/img/main/forexamplelogo.png',
                      ].map((String url) 
                        return new GridTile(
                            child: new Image.network(url, fit: BoxFit.cover, width: 12.0, height: 12.0,));
                      ).toList()),
                )
              ),

              new Padding(padding: new EdgeInsets.all(2.0)),
              new IconButton(
              splashColor: Colors.green,
              icon: new Icon(
                Icons.cancel,
                color: Colors.blue,
              ),
              onPressed: () 
                Navigator.of(context).pop();
              )
            ],
          ),
        ],
      ),
    );
  

这是我的错误日志...

══╡ 渲染库发现异常 ╞═════════════════════════════════════════════════ ════════ 在 performLayout() 期间引发了以下断言:RenderViewport 不支持返回固有尺寸。计算 内在维度将需要实例化 视口,它打败了视口懒惰的观点。如果你是 只是试图在主轴方向上收缩包裹视口, 考虑一个 RenderShrinkWrappingViewport 渲染对象 (ShrinkWrappingViewport 小部件),无需 实现内部维度 API。

【问题讨论】:

【参考方案1】:

这个错误本质上意味着有一个滚动区域或一个可以增长的小部件,并且您试图在其中放置另一个滚动区域而没有指定内部滚动区域应该有多大。当颤振试图计算各种事物的大小时,它不能,因为有两种不同的事物可以增长/缩小;特别是网格的垂直方向是您的问题。如果 gridview 计算了它所有子节点的大小,那么它可以根据它对所有其余的大小进行排序(如错误消息所述)。但是 gridview 的重点是显示大量数据,这些数据很可能会从屏幕上滚动出来,因此如果要进行该计算,在使用 gridview 的正常情况下可能会减慢速度。

我敢打赌,AlertDialog 有高度限制和/或不滚动,这就是为什么你没有看到它的问题。

要解决您的问题,您有两种选择。如果您将拥有大量项目(如果您描述了您实际尝试制作的内容,它将帮助我回答),请继续使用 gridview,但只需为其所在的容器分配一个高度。这样对话框可以很高兴地知道其所有子项的高度,并且网格可以在您给定的高度范围内调整自己的大小(TBH,我不确定您是否还需要定义宽度)。

另一个选项,如果您没有大量项目(即它们或多或少适合屏幕和/或您不希望它们滚动),请使用 wrap 而不是网格,它将直接布局您的所有项目。这样做的好处是,当您的方向发生变化时,它会很好地布置所有内容。

【讨论】:

感谢您的详尽解释。当我添加height: MediaQuery.of(context).size.height * 2, 时,GridView 工作,但我想我会使用换行。现在看起来很明显,但我相信您的回答会对其他人有所帮助。 尽管与我见过的几乎所有其他 UI 框架相比,flutter 文档都非常好,但有时仍然很难找到东西。很高兴我能帮上忙 =)

以上是关于Flutter - 如何在 SimpleDialog 框中显示 GridView?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:如何在 Flutter 中为 Firebase (FCM) 注册令牌订阅ToTopic

Flutter:如何在 google_maps_flutter 中为标记图标设置动画?

Flutter - 如何在 Flutter 应用上实现 News Count

flutter - 如何在 dart/flutter 中收听流值

如何使用 flutter_webview 插件在 Flutter 中启用位置?

如何在我的 Flutter 应用中添加渐变背景?