如何在Flutter中创建具有固定列的水平滚动表? [英] How to create a horizontally scrolling table with fixed column in Flutter?

查看:428
本文介绍了如何在Flutter中创建具有固定列的水平滚动表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一系列可以垂直滚动的表,每个表可能具有彼此不同的行数/列数.

I would like to create a series of tables that you can scroll through vertically, each of which may have a different number of rows/columns from each other.

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

Within each table, I would like to have the leftmost column frozen in place, and the remaining columns in that table to be horizontally scrollable, in case there are a number of columns that do not fit in the width of the screen. See screenshot:

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

My initial plan was to use a ListView for the page-level vertical scrolling between tables, and within each table, there is a Row of Columns, where the first column is a static width, and the remaining columns are enclosed within a horizontally scrolling ListView. The error I'm getting from Flutter is not helping me determine what I need to do, but it clearly has to do with having to set bounds on child Widgets.

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

Error: (Fixed 7/9/19 by wrapping horizontal ListView with a fixed height container and shrinkwrapping the ListView)

在performResize()期间引发了以下断言: 水平视口的宽度无限制. 视口沿滚动方向扩展以填充其容器. 视口被赋予了无限的水平空间,可以在其中进行扩展.这个情况 通常在将可滚动窗口小部件嵌套在另一个可滚动窗口小部件内时发生. 如果此窗口小部件始终嵌套在可滚动窗口小部件中,则无需使用视口,因为 孩子们总是会有足够的水平空间.在这种情况下,请考虑使用行 反而.否则,请考虑使用"shrinkWrap"属性(或ShrinkWrappingViewport)调整大小 视口的宽度与其子项的宽度之和.

The following assertion was thrown during performResize(): Horizontal viewport was given unbounded width. Viewports expand in the scrolling direction to fill their container.In this case, a horizontal viewport was given an unlimited amount of horizontal space in which to expand. This situation typically happens when a scrollable widget is nested inside another scrollable widget. If this widget is always nested in a scrollable widget there is no need to use a viewport because there will always be enough horizontal space for the children. In this case, consider using a Row instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size the width of the viewport to the sum of the widths of its children.

新错误19年7月9日:

New Error 7/9/19:

在布局期间引发了以下消息: RenderFlex在右侧溢出了74个像素. 溢出的RenderFlex的方向为Axis.horizo​​ntal. RenderFlex溢出的边缘已在渲染中用黄色和 黑色条纹的图案.这通常是因为内容对于RenderFlex而言太大. 考虑应用弹性系数(例如,使用扩展小部件)来强制使用 RenderFlex可以容纳在可用空间内,而不是按照其自然大小进行调整. 这被认为是错误情况,因为它表明存在不能被删除的内容. 见过.如果内容合法地大于可用空间,请考虑使用 在将ClipRect小部件放入Flex中或使用可滚动容器而不是Flex之前, 像ListView. 有问题的特定RenderFlex是:
RenderFlex#9bf67 relayoutBoundary = up5 OVERFLOWING
创建者:行←RepaintBoundary-[< 0>]←IndexedSemantics←
NotificationListener←保持活动←自动保持活动←SliverList←
SliverPadding←视口←IgnorePointer- [GlobalKey#74513]←语义←侦听器←⋯
parentData :(可以使用大小)
约束:BoxConstraints(w = 404.0,0.0 <= h <= Infinity)
尺寸:尺寸(404.0,300.0)
方向:水平
mainAxisAlignment:开始
mainAxisSize:max
crossAxisAlignment:中心
textDirection:ltr

The following message was thrown during layout: A RenderFlex overflowed by 74 pixels on the right. The overflowing RenderFlex has an orientation of Axis.horizontal. The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and black striped pattern. This is usually caused by the contents being too big for the RenderFlex. Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the RenderFlex to fit within the available space instead of being sized to their natural size. This is considered an error condition because it indicates that there is content that cannot be seen. If the content is legitimately bigger than the available space, consider clipping it with a ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex, like a ListView. The specific RenderFlex in question is:
RenderFlex#9bf67 relayoutBoundary=up5 OVERFLOWING
creator: Row ← RepaintBoundary-[<0>] ← IndexedSemantics ←
NotificationListener ← KeepAlive ← AutomaticKeepAlive ← SliverList ←
SliverPadding ← Viewport ← IgnorePointer-[GlobalKey#74513] ← Semantics ← Listener ← ⋯
parentData: (can use size)
constraints: BoxConstraints(w=404.0, 0.0<=h<=Infinity)
size: Size(404.0, 300.0)
direction: horizontal
mainAxisAlignment: start
mainAxisSize: max
crossAxisAlignment: center
textDirection: ltr

这是我最初遇到的问题,后来才被报道的第一个问题所困扰.我不明白为什么我的ListView没有创建可滚动的容器.

This was the issue I ran into originally before getting side-tracked with the first issue reported; I can't understand why my ListView is not creating a scrollable container.

代码:

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,
      ),
    );
  }
}

推荐答案

下面是一个简单的示例,结果如下:

Here is a quick example and this would be the result: Video

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),
              ),
            ),
          )
        ],
      ),
    ),
  );
}

这篇关于如何在Flutter中创建具有固定列的水平滚动表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆