如何在 Flutter 中创建带有固定列的水平滚动表?

Dan*_*len 16 flutter flutter-layout

我想创建一系列可以垂直滚动的表格,每个表格的行/列数可能不同。

在每个表中,我希望将最左边的列冻结到位,并且该表中的其余列可以水平滚动,以防有许多列不适合屏幕宽度。看截图:

例子

我最初的计划是使用ListView在表格之间进行页面级别的垂直滚动,并且在每个表格内,有一行列,其中第一列是静态宽度,其余列包含在水平滚动的ListView中. 我从 Flutter 得到的错误并没有帮助我确定我需要做什么,但它显然与必须在子 Widget 上设置边界有关。

错误:(通过用固定高度的容器包装水平 ListView 并收缩包装 ListView 来修复 7/9/19)

在 performResize() 期间抛出了以下断言:水平视口的宽度没有限制。视口在滚动方向上扩展以填充其容器。在这种情况下,水平视口被赋予无限量的水平空间来扩展。当可滚动小部件嵌套在另一个可滚动小部件中时,通常会发生这种情况。如果此小部件始终嵌套在可滚动小部件中,则无需使用视口,因为始终有足够的水平空间供子项使用。在这种情况下,请考虑改用 Row。否则,请考虑使用“shrinkWrap”属性(或 ShrinkWrappingViewport)将视口的宽度调整为其子项宽度的总和。

新错误 7/9/19:

布局期间抛出以下消息:A RenderFlex 在右侧溢出了 74 个像素。溢出的 RenderFlex 的方向为 Axis.horizo​​ntal。渲染中溢出的 RenderFlex 边缘已用黄黑条纹图案标记。这通常是由于 RenderFlex 的内容太大造成的。考虑应用 flex 因子(例如使用 Expanded 小部件)来强制 RenderFlex 的子项适应可用空间,而不是调整到它们的自然大小。这被视为错误情况,因为它表明存在无法看到的内容。如果内容合法地大于可用空间,请考虑在将其放入 flex 之前使用 ClipRect 小部件对其进行剪辑,或者使用可滚动容器而不是 Flex,就像一个列表视图。有问题的特定 RenderFlex 是:
RenderFlex#9bf67 relayoutBoundary=up5 溢出
创建者:行?重绘边界-[<0>] ? 索引语义?
通知监听器?活着 ?自动保持活动?白名单?
SliverPadding ? 视口?忽略指针-[GlobalKey#74513] ? 语义?听众??
parentData:(可以使用大小)
约束:BoxConstraints(w=404.0, 0.0<=h<=Infinity)
大小:Size(404.0, 300.0)
方向:水平
mainAxisAlignment:开始
mainAxisSize:max
crossAxisAlignment:center
textDirection:ltr

这是我最初遇到的问题,然后被报告的第一个问题转移到一边;我不明白为什么我的 ListView 没有创建可滚动容器。

代码:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      home: Scaffold(
        appBar: AppBar(
          title: Text('My App'),
          backgroundColor: Colors.teal[400],
        ),
        body: MyClass(),
      ),
    );
  }
}

const double headerCellWidth = 108.0;
const double cellPadding = 8.0;
const double focusedColumnWidth = 185.0;
const double rowHeight = 36.0;

class MyClass extends StatefulWidget {
  @override
  _MyClassState createState() => _MyClassState();
}

class _MyClassState extends State<MyClass> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: EdgeInsets.all(5.0),
      children: <Widget>[
        Row(
          children: <Widget>[
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Container(
                  color: Colors.grey,
                  padding: EdgeInsets.all(cellPadding),
                  width: headerCellWidth,
                ),
                HeaderCell('ABC'),
                HeaderCell('123'),
                HeaderCell('XYZ'),
              ],
            ),
            Container(
              height: 300.0,  // Could compute height with fixed rows and known number of rows in advance
              child: ListView(
                shrinkWrap: true,
                scrollDirection: Axis.horizontal,
                children: <Widget>[
                  Column(
                    children: <Widget>[
                      Container(
                        color: Colors.grey[300],
                        padding: EdgeInsets.all(cellPadding),
                        height: rowHeight,
                        width: focusedColumnWidth,
                      ),
                      NumberCell('89'),
                      NumberCell('92'),
                      NumberCell('91'),
                      NumberCell('90'),
                      NumberCell('91'),
                      NumberCell('89'),
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      Container(
                        color: Colors.grey[300],
                        padding: EdgeInsets.all(cellPadding),
                        height: rowHeight,
                        width: focusedColumnWidth,
                      ),
                      NumberCell('89'),
                      NumberCell('92'),
                      NumberCell('91'),
                      NumberCell('90'),
                      NumberCell('91'),
                      NumberCell('89'),
                    ],
                  ),
                ],
              ),
            ),
          ],
        ),
      ],
    );
  }
}

class HeaderCell extends StatelessWidget {
  HeaderCell(this.text);

  final String text;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: rowHeight,
      padding: EdgeInsets.all(cellPadding),
      width: headerCellWidth,
      child: Text(
        text,
        textAlign: TextAlign.left,
        overflow: TextOverflow.ellipsis,
        maxLines: 1,
        style: TextStyle(
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }
}

class NumberCell extends StatelessWidget {
  NumberCell(this.text);

  final String text;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: rowHeight,
      width: focusedColumnWidth,
      padding: EdgeInsets.all(cellPadding),
      child: Text(
        text,
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Pab*_*era 22

这是一个快速示例,结果如下:视频

List<Widget> _buildCells(int count) {
  return List.generate(
    count,
    (index) => Container(
      alignment: Alignment.center,
      width: 120.0,
      height: 60.0,
      color: Colors.white,
      margin: EdgeInsets.all(4.0),
      child: Text("${index + 1}", style: Theme.of(context).textTheme.title),
    ),
  );
}

List<Widget> _buildRows(int count) {
  return List.generate(
    count,
    (index) => Row(
      children: _buildCells(10),
    ),
  );
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(),
    body: SingleChildScrollView(
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: _buildCells(20),
          ),
          Flexible(
            child: SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: _buildRows(20),
              ),
            ),
          )
        ],
      ),
    ),
  );
}
Run Code Online (Sandbox Code Playgroud)